001: /*
002: ItsNat Java Web Application Framework
003: Copyright (C) 2007 Innowhere Software Services S.L., Spanish Company
004: Author: Jose Maria Arranz Santamaria
005:
006: This program is free software: you can redistribute it and/or modify
007: it under the terms of the GNU Affero General Public License as published by
008: the Free Software Foundation, either version 3 of the License, or
009: (at your option) any later version. See the GNU Affero General Public
010: License for more details. See the copy of the GNU Affero General Public License
011: included in this program. If not, see <http://www.gnu.org/licenses/>.
012: */
013:
014: package org.itsnat.impl.core;
015:
016: import org.itsnat.core.ItsNatException;
017: import org.itsnat.core.ItsNatServlet;
018: import org.itsnat.core.ItsNatServletConfig;
019: import org.itsnat.core.MarkupTemplate;
020: import java.io.File;
021: import java.util.HashMap;
022: import java.util.Map;
023: import java.util.Set;
024: import org.itsnat.impl.core.util.ThreadLocalDCL;
025: import org.xml.sax.InputSource;
026:
027: /**
028: *
029: * @author jmarranz
030: */
031: public abstract class MarkupTemplateImpl extends ItsNatUserDataImpl
032: implements MarkupTemplate {
033: protected ThreadLocal currentTemplateThreadLocal = ThreadLocalDCL
034: .newThreadLocal();
035: protected volatile MarkupTemplateVersionImpl currentTemplateVersion; // volatile evita en JDK 1.5 y superiores el problema del "Double-checked locking", para JVM 1.4 y menores ha de usarse el ThreadLocal
036: protected final String name;
037: protected final String mime;
038: protected final File file;
039: protected final InputSource source;
040: protected final ItsNatServletImpl servlet; // El servlet en el que se registró
041: protected String encoding; // Puede cambiar
042: protected boolean onLoadCachingDOMNodes;
043: protected boolean debugMode; // En fragmentos por ahora no influye en nada pero en el futuro podría
044: protected int clientErrorMode;
045: protected final boolean isHTML;
046: protected final boolean isXHTML;
047:
048: /**
049: * Creates a new instance of MarkupTemplateImpl
050: */
051: public MarkupTemplateImpl(String name, String mime, String path,
052: ItsNatServletImpl servlet) {
053: super (true);
054:
055: this .name = name;
056: this .mime = mime;
057:
058: path = path.trim(); // Los espacios al final y al principio hacen fallar a File en Linux
059: this .file = new File(path);
060: if (!file.exists())
061: throw new ItsNatException("File " + path
062: + " does not exist");
063: int index = path.indexOf("file:");
064: String url;
065: if (index != -1)
066: url = path; // Ya es URL
067: else
068: url = "file:" + path;
069:
070: this .source = new InputSource(url); // A día de hoy sólo admitimos paths pero en el futuro podrán ser streams etc (pasando el usuario directamente el InputSource)
071: this .servlet = servlet;
072:
073: ItsNatServletConfig servletConfig = servlet
074: .getItsNatServletConfig();
075:
076: this .encoding = servletConfig.getDefaultEncoding();
077:
078: if (isHTMLorXHTML()) {
079: // Como el mime no cambia no hay problema
080: this .isHTML = isHTML(getMIME());
081: this .isXHTML = isXHTML(getMIME());
082: } else {
083: this .isHTML = false;
084: this .isXHTML = false;
085: }
086:
087: this .onLoadCachingDOMNodes = servletConfig
088: .isOnLoadCacheStaticNodes(getMIME());
089:
090: this .debugMode = servletConfig.isDebugMode();
091: this .clientErrorMode = servletConfig.getClientErrorMode();
092: }
093:
094: public abstract boolean isHTMLorXHTML();
095:
096: public boolean isXHTML() {
097: return isXHTML;
098: }
099:
100: public boolean isHTML() {
101: return isHTML;
102: }
103:
104: public String getName() {
105: return name;
106: }
107:
108: public InputSource getInputSource() {
109: return source;
110: }
111:
112: public String getMIME() {
113: // No hacemos método set porque el dato se suministra ya por el constructor explícitamente
114: return mime;
115: }
116:
117: public String getEncoding() {
118: return encoding;
119: }
120:
121: public void setEncoding(String encoding) {
122: checkIsAlreadyUsed();
123: this .encoding = encoding;
124: }
125:
126: public boolean isOnLoadCacheStaticNodes() {
127: return onLoadCachingDOMNodes;
128: }
129:
130: public void setOnLoadCacheStaticNodes(boolean value) {
131: checkIsAlreadyUsed();
132: this .onLoadCachingDOMNodes = value;
133: }
134:
135: public boolean isDebugMode() {
136: return debugMode;
137: }
138:
139: public void setDebugMode(boolean debugMode) {
140: checkIsAlreadyUsed();
141: this .debugMode = debugMode;
142: }
143:
144: public int getClientErrorMode() {
145: return clientErrorMode;
146: }
147:
148: public void setClientErrorMode(int mode) {
149: checkIsAlreadyUsed();
150:
151: this .clientErrorMode = mode;
152: }
153:
154: private MarkupTemplateVersionImpl getNewestMarkupTemplateVersion(
155: long currentTimeStamp) {
156: // Ya existe un currentTemplateVersion, vemos si tenemos que crear otro porque ha cambiado el documento
157: if (currentTemplateVersion.isInvalid(currentTimeStamp)) {
158: synchronized (currentTemplateVersion) {
159: if (currentTemplateVersion.isInvalid(currentTimeStamp)) // por si acaso hubo un hilo concurrente esperando
160: {
161: this .currentTemplateVersion = newMarkupTemplateVersion(currentTimeStamp);
162: }
163: }
164: }
165: return currentTemplateVersion;
166: }
167:
168: public long getCurrentTimeStamp() {
169: if (!file.exists())
170: throw new ItsNatException("File " + file.getAbsoluteFile()
171: + " does not exist");
172: return file.lastModified();
173: }
174:
175: public MarkupTemplateVersionImpl getMarkupTemplateVersion() {
176: long currentTimeStamp = getCurrentTimeStamp();
177:
178: if (currentTemplateThreadLocal != null) // JVM 1.4 o menor
179: {
180: if (currentTemplateThreadLocal.get() == null) {
181: synchronized (this ) {
182: currentTemplateThreadLocal.set(Boolean.TRUE); // Este hilo así se entera que currentTemplateVersion está ya definido o se define ahora
183: if (currentTemplateVersion == null) {
184: this .currentTemplateVersion = newMarkupTemplateVersion(currentTimeStamp);
185: return currentTemplateVersion;
186: } else
187: return getNewestMarkupTemplateVersion(currentTimeStamp);
188: }
189: } else
190: return getNewestMarkupTemplateVersion(currentTimeStamp);
191: } else // JVM 1.5 y superior
192: {
193: if (currentTemplateVersion == null) {
194: // La primera vez que se accede a la página
195: synchronized (this ) {
196: if (currentTemplateVersion == null) // por si acaso hubo un hilo concurrente esperando
197: {
198: this .currentTemplateVersion = newMarkupTemplateVersion(currentTimeStamp);
199: }
200: return currentTemplateVersion; // No ha dado tiempo a que el archivo de la plantilla cambie en el caso de concurrencia de dos hilos
201: }
202: } else
203: return getNewestMarkupTemplateVersion(currentTimeStamp);
204: }
205: }
206:
207: public ItsNatServlet getItsNatServlet() {
208: return servlet;
209: }
210:
211: public ItsNatServletImpl getItsNatServletImpl() {
212: return servlet;
213: }
214:
215: public static boolean isHTMLorXHTML(String mime) {
216: // http://www.w3.org/TR/xhtml-media-types/
217: // http://www.xml.com/pub/a/2003/03/19/dive-into-xml.html
218: return (mime.equals("text/html") || mime
219: .equals("application/xhtml+xml"));
220: }
221:
222: public static boolean isXHTML(String mime) {
223: return mime.equals("application/xhtml+xml");
224: }
225:
226: public static boolean isHTML(String mime) {
227: return mime.equals("text/html");
228: }
229:
230: public abstract MarkupTemplateVersionImpl newMarkupTemplateVersion(
231: long timeStamp);
232:
233: public void checkIsAlreadyUsed() {
234: if (currentTemplateVersion != null)
235: throw new ItsNatException(
236: "Template is frozen because some document/fragment was already loaded");
237: }
238: }
|