Home » geronimo-2.2-source-release » org.apache.geronimo.deployment.xml » [javadoc | source]

    1   /**
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    */
   17   
   18   package org.apache.geronimo.deployment.xml;
   19   
   20   import java.io.BufferedInputStream;
   21   import java.io.IOException;
   22   import java.io.InputStream;
   23   import java.net.MalformedURLException;
   24   import java.net.URI;
   25   import java.util.Vector;
   26   
   27   import org.slf4j.Logger;
   28   import org.slf4j.LoggerFactory;
   29   import org.apache.geronimo.gbean.GBeanInfo;
   30   import org.apache.geronimo.gbean.GBeanInfoBuilder;
   31   import org.apache.xml.resolver.Catalog;
   32   import org.apache.xml.resolver.CatalogEntry;
   33   import org.apache.xml.resolver.CatalogException;
   34   import org.apache.xml.resolver.CatalogManager;
   35   import org.xml.sax.EntityResolver;
   36   import org.xml.sax.InputSource;
   37   import org.xml.sax.SAXException;
   38   
   39   /**
   40    * Implementation of EntityResolver that looks to the local filesystem.
   41    *
   42    * The implementation tries to resolve an entity via the following steps:
   43    *
   44    * <ul>
   45    *   <li>using a catalog file</li>
   46    *   <li>using a local repository</li>
   47    *   <li>using JAR files in Classpath</li>
   48    * </ul>
   49    *
   50    * The catalog resolving is based on the OASIS XML Catalog Standard.
   51    * OASIS seems to move it around.  Try
   52    * http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=entity
   53    * and the list of documents currently at
   54    * http://www.oasis-open.org/committees/documents.php?wg_abbrev=entity
   55    * An older version may be at
   56    * http://www.oasis-open.org/committees/entity/archives/spec-2001-08-01.html
   57    * and see http://www.oasis-open.org/html/a401.htm
   58    *
   59    * @version $Rev: 653740 $ $Date: 2008-05-06 03:44:18 -0700 (Tue, 06 May 2008) $
   60    */
   61   public class LocalEntityResolver implements EntityResolver {
   62       private static final Logger log = LoggerFactory.getLogger(LocalEntityResolver.class);
   63   
   64       /**
   65        * The used Catalog Manager
   66        */
   67       private final CatalogManager manager = new CatalogManager();
   68   
   69       /**
   70        * the XML Catalog
   71        */
   72       private Catalog catalog = null;
   73   
   74       /**
   75        * the URI of the catalog file
   76        */
   77       private URI catalogFileURI = null;
   78   
   79       /**
   80        * Local Repository where DTDs and Schemas are located
   81        */
   82       private URI localRepositoryURI = null;
   83   
   84       /**
   85        * Flag indicating if this resolver may return null to signal
   86        * the parser to open a regular URI connection to the system
   87        * identifier. Otherwise an exception is thrown.
   88        */
   89       private boolean failOnUnresolvable = false;
   90   
   91   
   92       public LocalEntityResolver(URI catalogFileURI, URI localRepositoryURI, boolean failOnUnresolvable) {
   93           this.catalogFileURI = catalogFileURI;
   94           setLocalRepositoryURI(localRepositoryURI);
   95           setFailOnUnresolvable(failOnUnresolvable);
   96           init();
   97       }
   98   
   99       /**
  100        * Sets the setFailOnUnresolvable flag.
  101        *
  102        * @param b value (true means that a SAXException is thrown
  103        * if the entity could not be resolved)
  104        */
  105       public void setFailOnUnresolvable(final boolean b) {
  106           failOnUnresolvable = b;
  107       }
  108   
  109       public boolean isFailOnUnresolvable() {
  110           return failOnUnresolvable;
  111       }
  112   
  113       public void setCatalogFileURI(final URI catalogFileURI) {
  114           this.catalogFileURI = catalogFileURI;
  115           init();
  116       }
  117   
  118       public URI getCatalogFileURI() {
  119           return this.catalogFileURI;
  120       }
  121   
  122       public URI getLocalRepositoryURI() {
  123           return localRepositoryURI;
  124       }
  125   
  126       public void setLocalRepositoryURI(URI string) {
  127           localRepositoryURI = string;
  128       }
  129   
  130       public void addPublicMapping(final String publicId, final String uri) {
  131   
  132           Vector args = new Vector();
  133           args.add(publicId);
  134           args.add(uri);
  135   
  136           addEntry("PUBLIC", args);
  137   
  138       }
  139   
  140       public void addSystemMapping(final String systemId, final String uri) {
  141   
  142           Vector args = new Vector();
  143           args.add(systemId);
  144           args.add(uri);
  145   
  146           addEntry("SYSTEM", args);
  147   
  148       }
  149   
  150       /**
  151        * Attempt to resolve the entity based on the supplied publicId and systemId.
  152        * First the catalog is queried with both publicId and systemId.
  153        * Then the local repository is queried with the file name part of the systemId
  154        * Then the classpath is queried with  the file name part of the systemId.
  155        *
  156        * Then, if failOnUnresolvable is true, an exception is thrown: otherwise null is returned.
  157        * @param publicId
  158        * @param systemId
  159        * @return
  160        * @throws SAXException
  161        * @throws IOException
  162        */
  163       public InputSource resolveEntity(
  164               final String publicId,
  165               final String systemId)
  166               throws SAXException, IOException {
  167   
  168           if (log.isTraceEnabled()) {
  169               log.trace("start resolving for " + entityMessageString(publicId, systemId));
  170           }
  171   
  172           InputSource source = resolveWithCatalog(publicId, systemId);
  173           if (source != null) {
  174               return source;
  175           }
  176   
  177           source = resolveWithRepository(publicId, systemId);
  178           if (source != null) {
  179               return source;
  180           }
  181   
  182           source = resolveWithClasspath(publicId, systemId);
  183           if (source != null) {
  184               return source;
  185           }
  186   
  187           String message = "could not resolve " + entityMessageString(publicId, systemId);
  188   
  189           if (failOnUnresolvable) {
  190               throw new SAXException(message);
  191           } else {
  192               log.debug(message);
  193           }
  194   
  195           return null;
  196       }
  197   
  198       /**
  199        * Try to resolve using the catalog file
  200        *
  201        * @param publicId the PublicId
  202        * @param systemId the SystemId
  203        * @return InputSource if the entity could be resolved. null otherwise
  204        * @throws MalformedURLException
  205        * @throws IOException
  206        */
  207       InputSource resolveWithCatalog(
  208               final String publicId,
  209               final String systemId)
  210               throws MalformedURLException, IOException {
  211   
  212           if (catalogFileURI == null) {
  213               return null;
  214           }
  215   
  216           String resolvedSystemId =
  217                   catalog.resolvePublic(guaranteeNotNull(publicId), systemId);
  218   
  219           if (resolvedSystemId != null) {
  220               if (log.isTraceEnabled()) {
  221                   log.trace("resolved " + entityMessageString(publicId, systemId) + " using the catalog file. result: " + resolvedSystemId);
  222               }
  223               return new InputSource(resolvedSystemId);
  224           }
  225   
  226           return null;
  227       }
  228   
  229       /**
  230        * Try to resolve using the local repository and only the supplied systemID filename.
  231        * Any path in the systemID will be removed.
  232        *
  233        * @param publicId the PublicId
  234        * @param systemId the SystemId
  235        * @return InputSource if the entity could be resolved. null otherwise
  236        */
  237       InputSource resolveWithRepository(
  238               final String publicId,
  239               final String systemId) {
  240   
  241           if (localRepositoryURI == null) {
  242               return null;
  243           }
  244   
  245           String fileName = getSystemIdFileName(systemId);
  246   
  247           if (fileName == null) {
  248               return null;
  249           }
  250   
  251           InputStream inputStream = null;
  252           URI resolvedSystemIDURI;
  253           try {
  254               resolvedSystemIDURI = localRepositoryURI.resolve(fileName);
  255               inputStream = resolvedSystemIDURI.toURL().openStream();
  256           } catch (IOException e) {
  257               return null;
  258           } catch (IllegalArgumentException e) {
  259               //typically "uri is not absolute"
  260               return null;
  261           }
  262           if (inputStream != null) {
  263               if (log.isTraceEnabled()) {
  264                   log.trace("resolved " + entityMessageString(publicId, systemId) + "with file relative to " + localRepositoryURI + resolvedSystemIDURI);
  265               }
  266               return new InputSource(inputStream);
  267           } else {
  268               return null;
  269           }
  270           /*
  271           String resolvedSystemId = null;
  272   
  273           File file = new File(localRepositoryURI, fileName);
  274           if (file.exists()) {
  275               resolvedSystemId = file.getAbsolutePath();
  276               if (log.isTraceEnabled()) {
  277                   log.trace(
  278                           "resolved "
  279                           + entityMessageString(publicId, systemId)
  280                           + "with file relative to "
  281                           + localRepositoryURI
  282                           + resolvedSystemId);
  283               }
  284               return new InputSource(resolvedSystemId);
  285           }
  286           return null;
  287           */
  288       }
  289   
  290       /**
  291        * Try to resolve using the the classpath and only the supplied systemID.
  292        * Any path in the systemID will be removed.
  293        *
  294        * @param publicId the PublicId
  295        * @param systemId the SystemId
  296        * @return InputSource if the entity could be resolved. null otherwise
  297        */
  298       InputSource resolveWithClasspath(
  299               final String publicId,
  300               final String systemId) {
  301   
  302           String fileName = getSystemIdFileName(systemId);
  303   
  304           if (fileName == null) {
  305               return null;
  306           }
  307   
  308           InputStream in =
  309                   getClass().getClassLoader().getResourceAsStream(fileName);
  310           if (in != null) {
  311               if (log.isTraceEnabled()) {
  312                   log.trace("resolved " + entityMessageString(publicId, systemId) + " via file found file on classpath: " + fileName);
  313               }
  314               InputSource is = new InputSource(new BufferedInputStream(in));
  315               is.setSystemId(systemId);
  316               return is;
  317           }
  318   
  319           return null;
  320       }
  321   
  322       /**
  323        * Guarantees a not null value
  324        */
  325       private String guaranteeNotNull(final String string) {
  326           return string != null ? string : "";
  327       }
  328   
  329       /**
  330        * Returns the SystemIds filename
  331        *
  332        * @param systemId SystemId
  333        * @return filename
  334        */
  335       private String getSystemIdFileName(final String systemId) {
  336   
  337           if (systemId == null) {
  338               return null;
  339           }
  340   
  341           int indexBackSlash = systemId.lastIndexOf("\\");
  342           int indexSlash = systemId.lastIndexOf("/");
  343   
  344           int index = Math.max(indexBackSlash, indexSlash);
  345   
  346           String fileName = systemId.substring(index + 1);
  347           return fileName;
  348       }
  349   
  350       /**
  351        * Constructs a debugging message string
  352        */
  353       private String entityMessageString(
  354               final String publicId,
  355               final String systemId) {
  356   
  357           StringBuffer buffer = new StringBuffer("entity with publicId '");
  358           buffer.append(publicId);
  359           buffer.append("' and systemId '");
  360           buffer.append(systemId);
  361           buffer.append("'");
  362           return buffer.toString();
  363   
  364       }
  365   
  366       /**
  367        * Adds a new Entry to the catalog
  368        */
  369       private void addEntry(String type, Vector args) {
  370           try {
  371               CatalogEntry entry = new CatalogEntry(type, args);
  372               catalog.addEntry(entry);
  373           } catch (CatalogException e) {
  374               throw new RuntimeException(e);
  375           }
  376       }
  377   
  378       /**
  379        * Loads mappings from configuration file
  380        */
  381       private void init() {
  382   
  383           if (log.isDebugEnabled()) {
  384               log.debug("init catalog file " + this.catalogFileURI);
  385           }
  386   
  387           manager.setUseStaticCatalog(false);
  388           manager.setCatalogFiles(this.catalogFileURI.toString());
  389           manager.setIgnoreMissingProperties(true);
  390           catalog = manager.getCatalog();
  391       }
  392   
  393       public static final GBeanInfo GBEAN_INFO;
  394   
  395       static {
  396           GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic("configurable local entity resolver", LocalEntityResolver.class);
  397   
  398           infoFactory.addAttribute("catalogFileURI", URI.class, true);
  399           infoFactory.addAttribute("localRepositoryURI", URI.class, true);
  400           infoFactory.addAttribute("failOnUnresolvable", boolean.class, true);
  401   
  402           infoFactory.addOperation("resolveEntity", new Class[]{String.class, String.class});
  403           infoFactory.addOperation("addPublicMapping", new Class[]{String.class, String.class});
  404           infoFactory.addOperation("addSystemMapping", new Class[]{String.class, String.class});
  405   
  406           infoFactory.setConstructor(new String[]{"catalogFileURI", "localRepositoryURI", "failOnUnresolvable"});
  407   
  408           GBEAN_INFO = infoFactory.getBeanInfo();
  409       }
  410   
  411       public static GBeanInfo getGBeanInfo() {
  412           return GBEAN_INFO;
  413       }
  414   
  415   }

Home » geronimo-2.2-source-release » org.apache.geronimo.deployment.xml » [javadoc | source]