Source Code Cross Referenced for MarkupTemplateVersionImpl.java in  » Ajax » ItsNat » org » itsnat » impl » core » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Ajax » ItsNat » org.itsnat.impl.core 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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 java.util.HashMap;
017:        import java.util.Iterator;
018:        import java.util.LinkedList;
019:        import java.util.Map;
020:        import org.itsnat.core.ItsNatDOMException;
021:        import org.itsnat.core.domutil.ItsNatDOMUtil;
022:        import org.itsnat.impl.core.dom.render.DOMRenderImpl;
023:        import org.w3c.dom.Attr;
024:        import org.w3c.dom.Document;
025:        import org.w3c.dom.DocumentFragment;
026:        import org.w3c.dom.Element;
027:        import org.w3c.dom.Node;
028:        import org.xml.sax.InputSource;
029:        import org.w3c.dom.CharacterData;
030:        import org.w3c.dom.NamedNodeMap;
031:        import org.w3c.dom.Text;
032:
033:        /**
034:         *
035:         * @author jmarranz
036:         */
037:        public abstract class MarkupTemplateVersionImpl extends
038:                MarkupContainerImpl {
039:            public static final String ITSNAT_NAMESPACE = "http://itsnat.org/itsnat";
040:            protected MarkupTemplateImpl markupTemplate;
041:            protected Document templateDoc;
042:            protected long timeStamp;
043:            protected DOMRenderImpl nodeRender; // Sirve para serializar nodos concretos no el documento completo    
044:            protected MarkupTemplateVersionDelegateImpl templateDelegate;
045:            protected Map elementCacheMap;
046:            protected LinkedList fragments = new LinkedList(); // Se recorrerá en multihilo no podemos ahorrar memoria con creación demorada
047:
048:            /**
049:             * Creates a new instance of MarkupTemplateVersionImpl
050:             */
051:            public MarkupTemplateVersionImpl(MarkupTemplateImpl markupDesc,
052:                    long timeStamp) {
053:                this .id = markupDesc.getItsNatServletImpl().generateUniqueId();
054:                this .markupTemplate = markupDesc;
055:                this .timeStamp = timeStamp;
056:
057:                this .templateDelegate = createMarkupTemplateVersionDelegate();
058:                this .templateDoc = parseDocument(markupDesc.getInputSource());
059:                this .nodeRender = DOMRenderImpl.getDOMRender(templateDoc,
060:                        getMIME(), getEncoding(), true);
061:
062:                // Resolvemos lo primero los includes, así permitimos que pueda cachearse su contenido
063:                // Hay que tener en cuenta que al incluir un fragmento los nodos pueden estar cacheados
064:                // con el sistema de cacheado de los fragmentos incluidos con <include>, que es diferente al del documento
065:                // por tanto puede haber un doble cacheado (que no tienen por qué interferir)
066:                Element rootElem = templateDoc.getDocumentElement();
067:                processCommentsIncludesInTree(rootElem);
068:            }
069:
070:            public boolean isOnLoadCacheStaticNodes() {
071:                return markupTemplate.isOnLoadCacheStaticNodes();
072:            }
073:
074:            protected abstract void doCacheDocument();
075:
076:            public boolean isUniqueIdGeneratorSync() {
077:                return true;
078:            }
079:
080:            public boolean isHTMLorXHTML() {
081:                return markupTemplate.isHTMLorXHTML();
082:            }
083:
084:            public boolean isXHTML() {
085:                return markupTemplate.isXHTML(); // No cambia
086:            }
087:
088:            public boolean isHTML() {
089:                return markupTemplate.isHTML(); // No cambia
090:            }
091:
092:            public String getId() {
093:                return id;
094:            }
095:
096:            public Document getDocument() {
097:                return templateDoc;
098:            }
099:
100:            public DOMRenderImpl getNodeDOMRender() {
101:                return nodeRender;
102:            }
103:
104:            public String getEncoding() {
105:                return markupTemplate.getEncoding();
106:            }
107:
108:            public String getMIME() {
109:                // El MIME en el template no puede cambiar, no hay problema de versiones
110:                return markupTemplate.getMIME();
111:            }
112:
113:            public boolean isInvalid(long newTimeStamp) {
114:                boolean invalid = (newTimeStamp > this .timeStamp);
115:                if (invalid)
116:                    return true;
117:
118:                // Seguimos con los fragmentos incluidos, si alguno ha sido cambiado en el disco duro el template padre es inválido y necesita recargarse
119:
120:                for (Iterator it = fragments.iterator(); it.hasNext();) {
121:                    DocFragmentTemplateVersionImpl docFragTemplateIncVersion = (DocFragmentTemplateVersionImpl) it
122:                            .next();
123:                    if (docFragTemplateIncVersion.isInvalid())
124:                        return true;
125:                }
126:
127:                return false; // Nada ha cambiado
128:            }
129:
130:            public boolean isInvalid() {
131:                long newTimeStamp = markupTemplate.getCurrentTimeStamp();
132:                return isInvalid(newTimeStamp);
133:            }
134:
135:            public boolean processCommentsIncludesInNode(Node node) {
136:                if (node.getNodeType() != Node.ELEMENT_NODE)
137:                    return false;
138:
139:                Element nodeElem = (Element) node;
140:                String namespace = nodeElem.getNamespaceURI();
141:                if ((namespace != null) && ITSNAT_NAMESPACE.equals(namespace)) {
142:                    String localName = nodeElem.getLocalName();
143:
144:                    if (localName.equals("include")) {
145:                        String fragName = nodeElem.getAttribute("name");
146:                        processIncludeReplacingNode(nodeElem, fragName);
147:                        return true;
148:                    } else if (localName.equals("comment")) {
149:                        nodeElem.getParentNode().removeChild(nodeElem);
150:
151:                        return true;
152:                    } else
153:                        throw new ItsNatDOMException("Unknown itsnat tag name:"
154:                                + localName, nodeElem);
155:                } else if (nodeElem.hasAttributes()) {
156:                    NamedNodeMap attribs = nodeElem.getAttributes();
157:                    for (int i = 0; i < attribs.getLength(); i++) {
158:                        Attr attr = (Attr) attribs.item(i);
159:                        namespace = attr.getNamespaceURI();
160:                        if ((namespace != null)
161:                                && ITSNAT_NAMESPACE.equals(namespace)) {
162:                            String localName = attr.getLocalName();
163:                            if (localName.equals("include")) {
164:                                String fragName = attr.getValue();
165:                                processIncludeReplacingNode(nodeElem, fragName);
166:                                nodeElem.removeAttributeNode(attr);
167:                            } else if (localName.equals("includeInside")) {
168:                                String fragName = attr.getValue();
169:                                processIncludeInsideNode(nodeElem, fragName);
170:                                nodeElem.removeAttributeNode(attr);
171:                            } else if (localName.equals("comment")) {
172:                                nodeElem.removeAttributeNode(attr);
173:                            }
174:                            // Pueden ser otros atributos con prefijo itsnat:
175:                        }
176:                    }
177:                }
178:
179:                return false; // No es ni include ni comment
180:            }
181:
182:            public DocumentFragment loadDocumentFragment(Element includeElem,
183:                    String fragName) {
184:                DocFragmentTemplateImpl docFragTemplateInc = (DocFragmentTemplateImpl) markupTemplate
185:                        .getItsNatServlet().getDocFragmentTemplate(fragName);
186:                if (docFragTemplateInc == null)
187:                    throw new ItsNatDOMException(
188:                            "Document fragment not found: " + fragName,
189:                            includeElem);
190:
191:                DocFragmentTemplateVersionImpl docFragTemplateIncVersion = docFragTemplateInc
192:                        .getDocFragmentTemplateVersion();
193:                fragments.add(docFragTemplateIncVersion);
194:
195:                return templateDelegate.loadDocumentFragmentIncluded(
196:                        docFragTemplateIncVersion, includeElem);
197:            }
198:
199:            public void processIncludeReplacingNode(Element includeElem,
200:                    String fragName) {
201:                DocumentFragment docFrag = loadDocumentFragment(includeElem,
202:                        fragName);
203:                Node parent = includeElem.getParentNode();
204:                parent.insertBefore(docFrag, includeElem);
205:                parent.removeChild(includeElem);
206:            }
207:
208:            public void processIncludeInsideNode(Element includeElem,
209:                    String fragName) {
210:                DocumentFragment docFrag = loadDocumentFragment(includeElem,
211:                        fragName);
212:
213:                ItsNatDOMUtil.removeAllChildren(includeElem); // Por si acaso no está vacío
214:                includeElem.appendChild(docFrag); // El DocumentFragment queda vacío (creo)   
215:            }
216:
217:            public void processCommentsIncludesInTree(Node node) {
218:                if (!processCommentsIncludesInNode(node))
219:                    processCommentsIncludesInChildren(node);
220:            }
221:
222:            public void processCommentsIncludesInChildren(Node parent) {
223:                Node child = parent.getFirstChild();
224:                while (child != null) {
225:                    Node nextChild = child.getNextSibling(); // Antes de que pueda ser removido/reemplazado 
226:
227:                    processCommentsIncludesInTree(child);
228:
229:                    child = nextChild;
230:                }
231:            }
232:
233:            private String serializeChildNodes(Element parent) {
234:                StringBuffer code = new StringBuffer();
235:                Node child = parent.getFirstChild();
236:                while (child != null) {
237:                    code.append(serializeNode(child));
238:
239:                    child = child.getNextSibling();
240:                }
241:                return code.toString();
242:            }
243:
244:            protected String serializeNode(Node node) {
245:                return templateDelegate.serializeNode(node);
246:            }
247:
248:            protected boolean isNodeCacheable(Node node,
249:                    LinkedList cacheableChildrenGlobal) {
250:                if (node instanceof  Element)
251:                    return isElementCacheable((Element) node,
252:                            cacheableChildrenGlobal);
253:                else if (node instanceof  CharacterData)
254:                    return isCharacterDataCacheable((CharacterData) node);
255:                else
256:                    return false;
257:                // Otros tipos (incluido el objeto Document), no sabemos como cachearlos 
258:                // o no tiene sentido (caso Document,DocumentFragment) y podrían tener variables que no consideramos analizar,
259:                // nos curamos en salud, evitarán que los nodos superiores sean cacheables 
260:                // pero hay que tener en cuenta que son nodos raros
261:                // en el contenido de un documento
262:            }
263:
264:            private boolean isCharacterDataCacheable(CharacterData node) {
265:                // Nodos de texto, comentarios etc. 
266:                // El objetivo en este caso no es reducir el número de objetos DOM 
267:                // pues el Text etc se mantendrá, pero en los documentos clonados
268:                // no aparecerá todo el rollo de texto estático repetidas veces.
269:                // Es cacheable si no contiene variables
270:                return !hasVariables(node.getData());
271:            }
272:
273:            protected boolean isElementCacheable(Element elem,
274:                    LinkedList cacheableChildrenGlobal) {
275:                // Es cacheable si el contenido (los hijos) no van a cambiar, es decir si son estáticos
276:
277:                if (isDeclaredNotCacheable(elem))
278:                    return false; // Ni el elemento ni los hijos son cacheables
279:                if (declaredAsComponent(elem))
280:                    return false; // Los componentes por su naturaleza modifican los nodos contenidos, por tanto ni el elemento ni los hijos son cacheables
281:
282:                boolean elementCacheable = !isElementNotCacheableByNamespace(elem);
283:                // Si false el elemento no es cacheable pero podrían serlo los hijos, es el caso de que el elemento no pueda ser usado con innerHTML pero los elementos hijo sí
284:
285:                // Los atributos aunque no sean estáticos no importa
286:                // pues es el contenido del nodo es el que se cachea realmente      
287:
288:                // Aunque sea elementCacheable = true los hijos puede ser que sean cacheables o todos o algunos
289:
290:                boolean childrenAreStatic = areChildElementStatic(elem,
291:                        cacheableChildrenGlobal);
292:
293:                return elementCacheable && childrenAreStatic;
294:            }
295:
296:            protected boolean areChildElementStatic(Element elem,
297:                    LinkedList cacheableChildrenGlobal) {
298:                // Un elemento puede cachearse si sus hijos son estáticos (salvo que haya otra razón)
299:
300:                if (!elem.hasChildNodes())
301:                    return true; // El elemento es cacheable desde el pto. de vista de los hijos (no tiene), otra cosa es que no merezca la pena pues el contenido es vacío, es importante devolver true y no false pues si devolvemos false hacemos creer que todo el árbol superior NO puede ser cacheable 
302:
303:                LinkedList cacheableChildrenLocal = new LinkedList();
304:                boolean allChildrenCacheable = true;
305:                Node child = elem.getFirstChild();
306:                while (child != null) {
307:                    if (!isNodeCacheable(child, cacheableChildrenLocal)) {
308:                        allChildrenCacheable = false;
309:                    } else {
310:                        // Si no son todos los hijos cacheables por alguna razón,
311:                        // entonces no podemos cachear el nodo padre (elemento o documento)
312:                        // Al menos cacheamos los nodos hijos cacheables
313:
314:                        cacheableChildrenLocal.add(child);
315:                    }
316:
317:                    child = child.getNextSibling();
318:                }
319:
320:                if (!allChildrenCacheable) {
321:                    // Si no son todos los hijos cacheables por alguna razón,
322:                    // entonces no podemos cachear todo el nodo (elemento o documento)
323:                    // Al menos cacheamos los nodos hijos cacheables
324:                    if (!cacheableChildrenLocal.isEmpty()) {
325:                        cacheableChildrenGlobal.addAll(cacheableChildrenLocal);
326:                    }
327:
328:                    return false;
329:                } else {
330:                    // El que todos los nodos hijo sean cacheables no implica que sean estáticos pues 
331:                    // pueden tener atributos no estáticos, si tienen atributos
332:                    // no estáticos no podemos cachear el nodo padre. 
333:                    // Sólo si los hijos son totalmente estáticos (contenido cacheable + atributos estáticos)
334:                    // podemos cachear el nodo
335:                    // Sabemos que todos los nodos al menos son cacheables
336:                    boolean allChildrenStatic = true;
337:                    child = elem.getFirstChild();
338:                    while (child != null) {
339:                        if (!areAttributesStatic(child)) {
340:                            allChildrenStatic = false;
341:                            break;
342:                        }
343:
344:                        child = child.getNextSibling();
345:                    }
346:
347:                    if (!allChildrenStatic && !cacheableChildrenLocal.isEmpty()) {
348:                        // No son estáticos todos, pero al menos cacheamos los hijos
349:                        cacheableChildrenGlobal.addAll(cacheableChildrenLocal);
350:                    }
351:
352:                    return allChildrenStatic;
353:                }
354:            }
355:
356:            private boolean isDeclaredNotCacheable(Element elem) {
357:                // atributo itsnat:nocache
358:                String nocache = elem.getAttributeNS(ITSNAT_NAMESPACE,
359:                        "nocache");
360:                return "true".equals(nocache);
361:            }
362:
363:            private boolean areAttributesStatic(Node node) {
364:                if (!node.hasAttributes())
365:                    return true;
366:
367:                boolean allStatic = true;
368:                NamedNodeMap attributes = node.getAttributes();
369:                for (int i = 0; i < attributes.getLength(); i++) {
370:                    Attr attr = (Attr) attributes.item(i);
371:                    if (hasVariables(attr.getValue())) {
372:                        allStatic = false;
373:                        break;
374:                    }
375:                }
376:
377:                return allStatic;
378:            }
379:
380:            private boolean hasVariables(String content) {
381:                int index = content.indexOf("${");
382:                return index != -1;
383:            }
384:
385:            public Document parseDocument(InputSource input) {
386:                return templateDelegate.parseDocument(input, getEncoding());
387:            }
388:
389:            public boolean declaredAsComponent(Element elem) {
390:                return templateDelegate.declaredAsComponent(elem);
391:            }
392:
393:            public boolean isElementNotCacheableByNamespace(Element elem) {
394:                return templateDelegate.isElementNotCacheableByNamespace(elem);
395:            }
396:
397:            protected void inspectNodeToCache(Node node) {
398:                LinkedList cacheableChildrenGlobal = new LinkedList();
399:                boolean isCacheable = isNodeCacheable(node,
400:                        cacheableChildrenGlobal);
401:                if (isCacheable)
402:                    addNodeToCache(node);
403:                else {
404:                    for (Iterator it = cacheableChildrenGlobal.iterator(); it
405:                            .hasNext();) {
406:                        Node child = (Node) it.next();
407:                        addNodeToCache(child);
408:                    }
409:                }
410:            }
411:
412:            protected void addNodeToCache(Node node) {
413:                if (node instanceof  Element)
414:                    addElementToCache((Element) node);
415:                else if (node instanceof  CharacterData)
416:                    addCharacterDataToCache((CharacterData) node);
417:                else
418:                    throw new ItsNatDOMException("INTERNAL ERROR", node);
419:            }
420:
421:            protected void addElementToCache(Element elem) {
422:                // No vale la pena obviamente cachear elementos sin hijos
423:                if (!elem.hasChildNodes())
424:                    return;
425:
426:                Node firstChild = elem.getFirstChild();
427:
428:                if ((firstChild.getNextSibling() == null)
429:                        && (firstChild instanceof  CharacterData)) {
430:                    // Elemento con un único nodo hijo y de texto            
431:                    addCharacterDataToCache((CharacterData) firstChild);
432:                } else {
433:                    String code = serializeChildNodes(elem); // No se expanden los nodos cacheados de fragmentos incluidos con nodos <include>, ya se hará cuando se envíe al cliente  
434:
435:                    ItsNatDOMUtil.removeAllChildren(elem);
436:
437:                    Document doc = elem.getOwnerDocument();
438:                    String markedCode = addToCache(code);
439:                    Text markNode = doc.createTextNode(markedCode);
440:                    elem.appendChild(markNode);
441:                }
442:            }
443:
444:            protected Map getElementCacheMap() {
445:                if (elementCacheMap == null)
446:                    this .elementCacheMap = new HashMap(); // Así ahorramos memoria si el cache está desactivado
447:                return elementCacheMap;
448:            }
449:
450:            public boolean hasCachedNodes() {
451:                return (elementCacheMap != null) || (usedTemplates != null);
452:            }
453:
454:            protected void addCharacterDataToCache(CharacterData node) {
455:                // El objetivo en este caso no es reducir el número de objetos DOM 
456:                // pues el Text etc se mantendrá, pero en los documentos clonados
457:                // no aparecerá todo el rollo de texto estático repetidas veces.
458:
459:                String value = node.getData();
460:                if (value.length() < 100)
461:                    return; // Menos de 100 letras no merece la pena, así excluimos nodos de texto cortos, separadores etc, pues la ganancia de cachear nodos de texto es únicamente para disminuir el tamaño de los documentos clonados y el "descacheado" lleva su tiempo
462:
463:                // Aunque estemos en la serialización del proceso de cacheo
464:                // puede haber nodos cacheados de fragmentos incluidos con nodos <include>
465:                // no expandimos dichos nodos cacheados, ya
466:                // se hará cuando se envíe el código al cliente        
467:
468:                String code = serializeNode(node);
469:                int nodeType = node.getNodeType();
470:                if ((nodeType == Node.COMMENT_NODE)
471:                        || (nodeType == Node.CDATA_SECTION_NODE)) {
472:                    String prefix = null;
473:                    String suffix = null;
474:                    if (nodeType == Node.COMMENT_NODE) {
475:                        prefix = "<!--";
476:                        suffix = "-->";
477:                    } else {
478:                        prefix = "<![CDATA[";
479:                        suffix = "]]>";
480:                    }
481:
482:                    // Quitamos el prefijo y sufijo pues nos interesa guardar el contenido
483:                    // pues al serializar de nuevo el nodo al enviar al cliente se añadirá
484:                    // de nuevo el prefijo/sufijo
485:                    code = removePrefixSuffix(code, prefix, suffix);
486:                } else if ((nodeType == Node.TEXT_NODE) && isXHTML()) {
487:                    // El serializador XHTML engloba el texto dentro de un <![CDATA[ ... ]]>
488:                    // pero como substituimos el texto por la marca al serializar el nodo finalmente
489:                    // de nuevo se añadirá <![CDATA[ ... ]]> existiendo por tanto dos erróneamente.
490:                    // Por tanto quitamos los de ahora
491:
492:                    String prefix = "<![CDATA[";
493:                    String suffix = "]]>";
494:                    code = removePrefixSuffix(code, prefix, suffix);
495:                }
496:
497:                String markCode = addToCache(code);
498:                node.setData(markCode);
499:            }
500:
501:            public static String removePrefixSuffix(String code, String prefix,
502:                    String suffix) {
503:                code = code.substring(prefix.length());
504:                code = code.substring(0, code.length() - suffix.length());
505:                return code;
506:            }
507:
508:            protected String addToCache(String code) {
509:                CachedNode cachedNode = new CachedNode(this , code);
510:                Map elementCacheMap = getElementCacheMap();
511:                elementCacheMap.put(cachedNode.getId(), cachedNode);
512:                return cachedNode.getMarkCode();
513:            }
514:
515:            public MarkupTemplateVersionImpl getUsedMarkupTemplateVersion(
516:                    String id) {
517:                if (getId().equals(id))
518:                    return this ;
519:                else
520:                    return super .getUsedMarkupTemplateVersion(id);
521:            }
522:
523:            protected abstract MarkupTemplateVersionDelegateImpl createMarkupTemplateVersionDelegate();
524:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.