1
2
3
4
5
6
7
8
9
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");
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";
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
86 final IExtensionRegistry r = Platform.getExtensionRegistry();
87
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");
98 if (factory != null)
99 SchemaPool.registerFactory(factory);
100 } catch (CoreException ex) {
101 EuroMath.log(IStatus.ERROR, 0,
102 "Error loading coordinator factory", ex);
103 }
104 }
105
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
123
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
135
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");
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 "
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");
202 final Element parent = cut.from.parentElement;
203 if (parent == null)
204 throw new IllegalArgumentException(
205 "Pointer does not point into an element");
206 if (!parent.isSameNode(cut.to.parentElement))
207 throw new IllegalArgumentException(
208 "Both pointers must point into same element");
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
215
216
217 public String isValid(String newText) {
218 return valueRule.getErrorMessage(newText);
219 }
220 };
221 }
222 }