/***************************************************************************** * This file is part of Rinzo * * Author: Claudio Cancinos * WWW: https://sourceforge.net/projects/editorxml * Copyright (C): 2008, Claudio Cancinos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; If not, see <http://www.gnu.org/licenses/> ****************************************************************************/ package ar.com.tadp.xml.rinzo.core.model.tags.dtd; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.apache.commons.lang.StringUtils; import ar.com.tadp.xml.rinzo.core.model.XMLNode; import ar.com.tadp.xml.rinzo.core.model.tags.AttributeDefinition; import ar.com.tadp.xml.rinzo.core.model.tags.OnlyNameTypeTagDefinition; import ar.com.tadp.xml.rinzo.core.model.tags.TagTypeDefinition; import ar.com.tadp.xml.rinzo.core.model.tags.XMLTagDefinitionProvider; import ar.com.tadp.xml.rinzo.core.resources.cache.DocumentCache; import ar.com.tadp.xml.rinzo.core.resources.cache.DocumentStructureDeclaration; import ar.com.tadp.xml.rinzo.core.utils.FileUtils; import com.wutka.dtd.DTD; import com.wutka.dtd.DTDAttlist; import com.wutka.dtd.DTDAttribute; import com.wutka.dtd.DTDComment; import com.wutka.dtd.DTDElement; import com.wutka.dtd.DTDOutput; import com.wutka.dtd.DTDParser; /** * @author ccancinos * */ public class DTDTagDefinitionProvider implements XMLTagDefinitionProvider { private DocumentStructureDeclaration documentStructureDeclaration; private String fileName; private Map<String, TagTypeDefinition> tags = new HashMap<String, TagTypeDefinition>(); private Map<String, Map<String, DTDComment>> attributes = new HashMap<String, Map<String, DTDComment>>(); private String rootNodeName; private String dtdPath; private long lastModified; public DTDTagDefinitionProvider(String fileName, String rootNodeName, DocumentStructureDeclaration structureDeclaration) { try { this.fileName = fileName; this.rootNodeName = rootNodeName; this.documentStructureDeclaration = structureDeclaration; this.dtdPath = FileUtils.resolveURI(this.fileName, this.documentStructureDeclaration.getSystemId()) .toString(); this.updateDefinition(); } catch (URISyntaxException e) { throw new RuntimeException(e); } } public void setDefinition(String fileName, DocumentStructureDeclaration structureDeclaration) { String definition = null; try { definition = FileUtils.resolveURI(this.fileName, this.documentStructureDeclaration.getSystemId()).toString(); } catch (URISyntaxException e) { } if (!fileName.equals(this.fileName) || (definition != null && (!structureDeclaration.equals(this.documentStructureDeclaration) || this.isDefinitionUpdated(definition)))) { this.updateDefinition(); if (definition != null && (!structureDeclaration.equals(this.documentStructureDeclaration) || this.isDefinitionUpdated(definition))) { this.documentStructureDeclaration = structureDeclaration; this.dtdPath = definition; this.setLastDefinitionUpdate(definition); } } this.fileName = fileName; } /** * * @deprecated use setDefinition */ public void setFileName(String fileName) { if (!fileName.equals(this.fileName)) { this.updateDefinition(); } this.fileName = fileName; } /** * * @deprecated use setDefinition */ public void setDocumentDefinition(DocumentStructureDeclaration structureDeclaration) { try { String definition = FileUtils.resolveURI(this.fileName, this.documentStructureDeclaration.getSystemId()).toString(); if (!structureDeclaration.equals(this.documentStructureDeclaration) || this.isDefinitionUpdated(definition)) { this.updateDefinition(); this.documentStructureDeclaration = structureDeclaration; this.dtdPath = definition; this.setLastDefinitionUpdate(definition); } } catch (URISyntaxException e) { throw new RuntimeException(e); } } protected boolean isDefinitionUpdated(String definitionPath) { try { return this.lastModified < new File(definitionPath).lastModified(); } catch (Exception e) { return false; } } protected void setLastDefinitionUpdate(String definitionPath) { try { this.lastModified = new File(definitionPath).lastModified(); } catch (Exception e) { } } public TagTypeDefinition getTagDefinition(XMLNode node) { String tagName = node.getTagName(); if (StringUtils.isEmpty(tagName)) { return new TagTypeDefinition() { public AttributeDefinition getAttribute(String attributeName) { return null; } public Collection<AttributeDefinition> getAttributes() { return null; } public String getComment() { return null; } public Collection<TagTypeDefinition> getInnerTags() { Collection<TagTypeDefinition> c = new ArrayList<TagTypeDefinition>(); c.add(tags.get(rootNodeName)); return c; } public String getName() { return null; } public String getNamespace() { return ""; } }; } TagTypeDefinition tagDefinition = this.tags.get(tagName); return tagDefinition != null ? tagDefinition : new OnlyNameTypeTagDefinition(tagName); } /** * Se encarga de mapear las definiciones que se encuentran en el schema */ private void updateDefinition() { String dtdLocation = DocumentCache.getInstance().getLocation(this.documentStructureDeclaration.getPublicId(), this.dtdPath); this.parseElementsFrom(this.getDTD(dtdLocation)); } private void parseElementsFrom(DTD dtd) { DTDComment comment = null; for (Iterator<Object> iter = Arrays.asList(dtd.getItems()).iterator(); iter.hasNext();) { DTDOutput output = (DTDOutput) iter.next(); if (output instanceof DTDComment) { comment = (DTDComment) output; } if (output instanceof DTDElement) { this.addTagDefinition((DTDElement) output, comment); comment = null; } if (output instanceof DTDAttlist) { this.addAttrDefinition((DTDAttlist) output, comment); comment = null; } } } private DTD getDTD(String dtdLocation) { try { InputStream inputStream = new FileInputStream(dtdLocation); Reader reader = new InputStreamReader(inputStream); DTDParser parser = new DTDParser(reader); return parser.parse(); } catch (Exception e) { throw new RuntimeException("Trying to read the DTD specification in \"" + dtdLocation + "\"", e); } } private void addTagDefinition(DTDElement element, DTDComment comment) { this.tags.put(element.getName(), new DTDTagTypeDefinition(element, comment, this.tags, this.attributes.get(element.getName()))); } private void addAttrDefinition(DTDAttlist output, DTDComment comment) { if (!this.attributes.containsKey(output.getName())) { this.attributes.put(output.getName(), new HashMap<String, DTDComment>()); } Map<String, DTDComment> attr = this.attributes.get(output.getName()); for (DTDAttribute element : output.getAttribute()) { attr.put(element.getName(), comment); } } }