View Javadoc

1   /*
2    * Created on Jun 11, 2006. Copyright 2006-2007 Martin Vysny. This file is
3    * protected by the Mozilla Public License version 1.1 (the "License"); you may
4    * not use this file except in compliance with the License. You may obtain a
5    * copy of the License at http://euromath2.sourceforge.net/license.html Unless
6    * required by applicable law or agreed to in writing, software distributed
7    * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
8    * CONDITIONS OF ANY KIND, either express or implied. See the License for the
9    * specific language governing permissions and limitations under the License.
10   */
11  package sk.uniba.euromath.document.schema;
12  import java.net.MalformedURLException;
13  import java.net.URISyntaxException;
14  import java.net.URL;
15  import java.util.Arrays;
16  import java.util.Collections;
17  import java.util.HashSet;
18  import java.util.List;
19  import java.util.Set;
20  import org.eclipse.core.runtime.CoreException;
21  import org.eclipse.core.runtime.IConfigurationElement;
22  import org.eclipse.core.runtime.IExtensionPoint;
23  import org.eclipse.core.runtime.IExtensionRegistry;
24  import org.eclipse.core.runtime.IStatus;
25  import org.eclipse.core.runtime.Platform;
26  import org.eclipse.jface.dialogs.IInputValidator;
27  import org.w3c.dom.Element;
28  import org.xml.sax.Attributes;
29  import sk.baka.ikslibs.IQNameFilter;
30  import sk.baka.ikslibs.QNameFilters;
31  import sk.baka.ikslibs.interval.DOMInterval;
32  import sk.baka.ikslibs.levelmapper.IdDomMapper;
33  import sk.baka.ikslibs.ptr.DomPointer;
34  import sk.baka.ikslibs.sax.AttributeReplacer;
35  import sk.baka.ikslibs.sax.AttributesAdapter;
36  import sk.baka.xml.gene.ExportUtils;
37  import sk.baka.xml.schematic.DocumentSchema;
38  import sk.baka.xml.schematic.IValidationContext;
39  import sk.baka.xml.schematic.SchemaPool;
40  import sk.baka.xml.schematic.msv.SchemaFactoryImpl;
41  import sk.baka.xml.schematic.pluginterface.ISchemaFactory;
42  import sk.baka.xml.schematic.rules.ElementRule;
43  import sk.baka.xml.schematic.rules.IValueRule;
44  import sk.uniba.euromath.EuroMath;
45  import sk.uniba.euromath.config.EuromathConfig;
46  import sk.uniba.euromath.config.bind.NamespaceType;
47  import sk.uniba.euromath.config.bind.SchemaType;
48  /***
49   * Schematic initializer and helper.
50   * @author Martin Vysny
51   */
52  public final class SchematicUtils {
53  	/***
54  	 * Prevent instantiation.
55  	 */
56  	private SchematicUtils() {
57  		super();
58  	}
59  	/***
60  	 * Singleton instance of the schema pool.
61  	 */
62  	private static SchemaPool poolInstance = null;
63  	/***
64  	 * Retrieves schema pool instance.
65  	 * @return pool instance, never <code>null</code>.
66  	 */
67  	public static SchemaPool getPool() {
68  		if (poolInstance == null)
69  			throw new IllegalStateException("Call initializeSchematic() first"); //$NON-NLS-1$
70  		return poolInstance;
71  	}
72  	/***
73  	 * ID of extension point for {@link ISchemaFactory schema factory}
74  	 * instances.
75  	 */
76  	public static final String SCHEMA_FACTORY_EXTENSION_POINT_ID = "sk.uniba.euromath.ISchemaFactory"; //$NON-NLS-1$
77  	/***
78  	 * Initializes the schematic library by registering all known schema
79  	 * factories.
80  	 */
81  	public static void initializeSchematic() {
82  		if (poolInstance != null)
83  			return;
84  		poolInstance = new SchemaPool(new EM2ValidationContext());
85  		// register schema factories using the extension points.
86  		final IExtensionRegistry r = Platform.getExtensionRegistry();
87  		// coordinator factories
88  		final IExtensionPoint coordinatorFactoryPoint = r
89  				.getExtensionPoint(SCHEMA_FACTORY_EXTENSION_POINT_ID);
90  		if (coordinatorFactoryPoint == null)
91  			throw new AssertionError();
92  		final IConfigurationElement[] elements = coordinatorFactoryPoint
93  				.getConfigurationElements();
94  		for (IConfigurationElement element : elements) {
95  			try {
96  				final ISchemaFactory factory = (ISchemaFactory) element
97  						.createExecutableExtension("class"); //$NON-NLS-1$
98  				if (factory != null)
99  					SchemaPool.registerFactory(factory);
100 			} catch (CoreException ex) {
101 				EuroMath.log(IStatus.ERROR, 0,
102 						"Error loading coordinator factory", ex); //$NON-NLS-1$
103 			}
104 		}
105 		// register schema files from config file.
106 		registerSchemaFromConfig();
107 	}
108 	/***
109 	 * Filter that filters out all XML-reserved qnames as well as gene:id
110 	 * attribute.
111 	 */
112 	public static final IQNameFilter METAATRIBUTE_FILTER = QNameFilters.and(
113 			QNameFilters.XML_RESERVED_FILTER, QNameFilters.not(QNameFilters
114 					.filterNamespace(Collections
115 							.singleton(ExportUtils.GENE_ID_ATTRIBUTE_QNAME
116 									.getNamespaceURI()))));
117 	/***
118 	 * Provides nameroots defined in EuroMath config file.
119 	 */
120 	private static class EM2ValidationContext implements IValidationContext {
121 		/*
122 		 * (non-Javadoc)
123 		 * @see sk.baka.xml.schematic.IValidationContext#getAttributes(org.w3c.dom.Element)
124 		 */
125 		public Attributes getAttributes(Element element) {
126 			if (element.getAttributes() == null)
127 				return null;
128 			final AttributesAdapter elementAttrs = new AttributesAdapter();
129 			elementAttrs.attrs = element.getAttributes();
130 			return AttributeReplacer.createDeleter(elementAttrs,
131 					METAATRIBUTE_FILTER);
132 		}
133 		/*
134 		 * (non-Javadoc)
135 		 * @see sk.baka.xml.schematic.IValidationContext#getNameroots(java.lang.String)
136 		 */
137 		public Set<String> getNameroots(final String namespace) {
138 			final NamespaceType nt = EuromathConfig.getNamespace(namespace);
139 			if (nt.getSchema().getRootElements() != null) {
140 				final String[] rootLocalnames = nt.getSchema()
141 						.getRootElements().split("//s"); //$NON-NLS-1$
142 				return new HashSet<String>(Arrays.asList(rootLocalnames));
143 			}
144 			return null;
145 		}
146 	}
147 	/***
148 	 * Registers all schema files defined in the config file to Schematic
149 	 * framework.
150 	 */
151 	@SuppressWarnings("unchecked")
152 	private static void registerSchemaFromConfig() {
153 		final List<NamespaceType> ns = EuromathConfig.getConfig()
154 				.getNamespaces().getNamespace();
155 		for (NamespaceType nt : ns) {
156 			if (nt.getSchema() != null) {
157 				try {
158 					final SchemaType st = nt.getSchema();
159 					final URL url = resolve(st.getLocationUrl());
160 					poolInstance.getDefaultFactory().registerSchema(
161 							nt.getNamespaceUri(),
162 							new SchemaFactoryImpl.SchemaMetadataBean(url, st
163 									.isAllowOtherNs()));
164 				} catch (Exception ex) {
165 					EuroMath.log(IStatus.ERROR, 0, "Failed to load schema for " //$NON-NLS-1$
166 							+ nt.getNamespaceUri(), ex);
167 				}
168 			}
169 		}
170 	}
171 	/***
172 	 * Resolves specified relative url to loadable (system) absolute URL.
173 	 * @param url url from config file, relative to schema directory, which must
174 	 * be resolved.
175 	 * @return System URL
176 	 * @throws URISyntaxException
177 	 * @throws MalformedURLException
178 	 */
179 	private static URL resolve(String url) throws MalformedURLException,
180 			URISyntaxException {
181 		return EuromathConfig.getSchemaLoc().resolve(url);
182 	}
183 	/***
184 	 * Creates text validator. The validator will detect the text rule and acts
185 	 * as if text between two pointers was cut out and replaced by string given
186 	 * to the validator.
187 	 * @param schema the document schema instance.
188 	 * @param cut the interval denoting text being deleted or replaced. Must not
189 	 * be <code>null</code>. Caller must ensure that there are no elements
190 	 * covered by this interval. between the two pointers.
191 	 * @return validator that validates string
192 	 * {@link IdDomMapper#getTextTo(DomPointer) getTextTo(cutFrom)} +
193 	 * given_string +
194 	 * {@link IdDomMapper#getTextFrom(DomPointer) getTextFrom(cutTo)}. Never
195 	 * <code>null</code>.
196 	 */
197 	public static IInputValidator createTextValidator(
198 			final DocumentSchema schema, final DOMInterval cut) {
199 		if (cut.from.inEntity() || cut.to.inEntity())
200 			throw new IllegalArgumentException(
201 					"At least one of the pointers points into an entity"); //$NON-NLS-1$
202 		final Element parent = cut.from.parentElement;
203 		if (parent == null)
204 			throw new IllegalArgumentException(
205 					"Pointer does not point into an element"); //$NON-NLS-1$
206 		if (!parent.isSameNode(cut.to.parentElement))
207 			throw new IllegalArgumentException(
208 					"Both pointers must point into same element"); //$NON-NLS-1$
209 		final ElementRule rule = schema.getElementRule(parent);
210 		final IValueRule valueRule = rule.newTextValidator(cut.from.ip,
211 				cut.to.ip);
212 		return new IInputValidator() {
213 			/*
214 			 * (non-Javadoc)
215 			 * @see org.eclipse.jface.dialogs.IInputValidator#isValid(java.lang.String)
216 			 */
217 			public String isValid(String newText) {
218 				return valueRule.getErrorMessage(newText);
219 			}
220 		};
221 	}
222 }