001    package com.oxygenxml.validate.nvdl;
002    
003    import com.thaiopensource.util.PropertyId;
004    import com.thaiopensource.util.PropertyMap;
005    import com.thaiopensource.util.PropertyMapBuilder;
006    import com.thaiopensource.validate.IncorrectSchemaException;
007    import com.thaiopensource.validate.Option;
008    import com.thaiopensource.validate.Schema;
009    import com.thaiopensource.validate.SchemaReader;
010    import com.thaiopensource.validate.ValidateProperty;
011    import com.thaiopensource.validate.auto.AutoSchemaReader;
012    import com.thaiopensource.validate.auto.SchemaFuture;
013    import com.thaiopensource.validate.auto.SchemaReceiver;
014    import com.thaiopensource.validate.auto.SchemaReceiverFactory;
015    import com.thaiopensource.validate.rng.CompactSchemaReader;
016    import com.thaiopensource.validate.rng.SAXSchemaReader;
017    import org.xml.sax.InputSource;
018    import org.xml.sax.SAXException;
019    import org.xml.sax.XMLReader;
020    
021    import java.io.IOException;
022    import java.net.URL;
023    
024    /**
025     * Schema receiver implementation for NVDL schemas. 
026     *
027     */
028    class SchemaReceiverImpl implements SchemaReceiver {
029      /**
030       * Relax NG schema for nvdl schemas.
031       */
032      private static final String NVDL_SCHEMA = "nvdl.rng";
033      /**
034       * The type used for specifying RNC schemas.
035       */
036      private static final String RNC_MEDIA_TYPE = "application/x-rnc";
037      
038      /**
039       * Properties.
040       */
041      private final PropertyMap properties;
042      
043      /**
044       * Flag indicating if we need to check only attributes,
045       * that means the root element is just a placeholder for the attributes.
046       */
047      private final boolean attributesSchema;
048      
049      /**
050       * The schema reader capable of parsing the input schema file.
051       * It will be an auto schema reader as NVDL is XML.
052       */
053      private final SchemaReader autoSchemaReader;
054      
055      /**
056       * Schema object created by this schema receiver.
057       */
058      private Schema nvdlSchema = null;
059      
060      /**
061       * Required properties.
062       */
063      private static final PropertyId subSchemaProperties[] = {
064        ValidateProperty.ERROR_HANDLER,
065        ValidateProperty.XML_READER_CREATOR,
066        ValidateProperty.ENTITY_RESOLVER,
067        SchemaReceiverFactory.PROPERTY,
068      };
069    
070      /**
071       * Creates a schema receiver for NVDL schemas.
072       * 
073       * @param properties Properties.
074       */
075      public SchemaReceiverImpl(PropertyMap properties) {
076        this.attributesSchema = properties.contains(NvdlProperty.ATTRIBUTES_SCHEMA);
077        PropertyMapBuilder builder = new PropertyMapBuilder();
078        for (int i = 0; i < subSchemaProperties.length; i++) {
079          Object value = properties.get(subSchemaProperties[i]);
080          if (value != null)
081            builder.put(subSchemaProperties[i], value);
082        }
083        this.properties = builder.toPropertyMap();
084        this.autoSchemaReader = new AutoSchemaReader(SchemaReceiverFactory.PROPERTY.get(properties));
085      }
086    
087      /**
088       * 
089       */
090      public SchemaFuture installHandlers(XMLReader xr) {
091        PropertyMapBuilder builder = new PropertyMapBuilder(properties);
092        if (attributesSchema)
093          NvdlProperty.ATTRIBUTES_SCHEMA.add(builder);
094        return new SchemaImpl(builder.toPropertyMap()).installHandlers(xr, this);
095      }
096    
097      Schema getNvdlSchema() throws IOException, IncorrectSchemaException, SAXException {
098       if (nvdlSchema == null) {
099          String className = SchemaReceiverImpl.class.getName();
100          String resourceName = className.substring(0, className.lastIndexOf('.')).replace('.', '/') + "/resources/" + NVDL_SCHEMA;
101          URL nvdlSchemaUrl = getResource(resourceName);
102         nvdlSchema = SAXSchemaReader.getInstance().createSchema(new InputSource(nvdlSchemaUrl.toString()),
103                                                                  properties);
104        }
105        return nvdlSchema;
106      }
107    
108      /**
109       * Get a resource using this class class loader.
110       * @param resourceName the resource.
111       * @return An URL pointing to the resource.
112       */
113      private static URL getResource(String resourceName) {
114        ClassLoader cl = SchemaReceiverImpl.class.getClassLoader();
115        // XXX see if we should borrow 1.2 code from Service
116        if (cl == null)
117          return ClassLoader.getSystemResource(resourceName);
118        else
119          return cl.getResource(resourceName);
120      }
121    
122      /**
123       * Get the properties.
124       * @return a PropertyMap.
125       */
126      PropertyMap getProperties() {
127        return properties;
128      }
129    
130      /**
131       * Creates a child schema. This schema is referred in a validate action.
132       * 
133       * @param inputSource The input source for the schema.
134       * @param schemaType The schema type.
135       * @param options Options specified for this schema in the NVDL script.
136       * @param isAttributesSchema Flag indicating if the schema should be modified
137       * to check attributes only. 
138       * @return
139       * @throws IOException In case of IO problems.
140       * @throws IncorrectSchemaException In case of invalid schema.
141       * @throws SAXException In case if XML problems while creating the schema.
142       */
143      Schema createChildSchema(InputSource inputSource, String schemaType, PropertyMap options, boolean isAttributesSchema) throws IOException, IncorrectSchemaException, SAXException {
144        SchemaReader reader = isRnc(schemaType) ? CompactSchemaReader.getInstance() : autoSchemaReader;
145        PropertyMapBuilder builder = new PropertyMapBuilder(properties);
146        if (isAttributesSchema)
147          NvdlProperty.ATTRIBUTES_SCHEMA.add(builder);
148        for (int i = 0, len = options.size(); i < len; i++)
149          builder.put(options.getKey(i), options.get(options.getKey(i)));
150        return reader.createSchema(inputSource, builder.toPropertyMap());
151      }
152    
153      /**
154       * Get an option for the given URI.
155       * @param uri The URI for an option.
156       * @return Either the option from the auto schema reader or 
157       * from the compact schema reader.
158       */
159      Option getOption(String uri) {
160        Option option = autoSchemaReader.getOption(uri);
161        if (option != null)
162          return option;
163        return CompactSchemaReader.getInstance().getOption(uri);
164      }
165    
166      /**
167       * Checks is a schema type is RNC.
168       * @param schemaType The schema type specification.
169       * @return true if the schema type refers to a RNC schema.
170       */
171      private static boolean isRnc(String schemaType) {
172        if (schemaType == null)
173          return false;
174        schemaType = schemaType.trim();
175        return schemaType.equals(RNC_MEDIA_TYPE);
176      }
177    }