1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.db.services.adaption;
15 import java.io.StringReader;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.HashMap;
20 import java.util.List;
23 import javax.xml.parsers.DocumentBuilder;
24 import javax.xml.parsers.DocumentBuilderFactory;
26 import org.eclipse.core.runtime.Path;
27 import org.eclipse.core.runtime.Platform;
28 import org.osgi.framework.Bundle;
29 import org.osgi.framework.BundleContext;
30 import org.simantics.db.ReadGraph;
31 import org.simantics.db.Resource;
32 import org.simantics.db.Session;
33 import org.simantics.db.adaption.Adapter;
34 import org.simantics.db.adaption.AdapterInstaller;
35 import org.simantics.db.adaption.AdaptionService;
36 import org.simantics.db.common.request.ReadRequest;
37 import org.simantics.db.exception.DatabaseException;
38 import org.simantics.db.services.adaption.reflection.AdaptingDynamicAdapter2;
39 import org.simantics.db.services.adaption.reflection.AtMostOneRelatedResource2;
40 import org.simantics.db.services.adaption.reflection.ConstantAdapter;
41 import org.simantics.db.services.adaption.reflection.GraphObject2;
42 import org.simantics.db.services.adaption.reflection.IDynamicAdapter2;
43 import org.simantics.db.services.adaption.reflection.OrderedSetResources2;
44 import org.simantics.db.services.adaption.reflection.ReflectionAdapter2;
45 import org.simantics.db.services.adaption.reflection.RelatedResources2;
46 import org.simantics.db.services.adaption.reflection.SingleRelatedResource2;
47 import org.simantics.db.services.adaption.reflection.StaticMethodAdapter;
48 import org.simantics.db.services.adaption.reflection.ThisResource2;
49 import org.simantics.scl.reflection.OntologyVersions;
50 import org.simantics.utils.FileUtils;
51 import org.w3c.dom.DOMException;
52 import org.w3c.dom.Document;
53 import org.w3c.dom.NamedNodeMap;
54 import org.w3c.dom.Node;
55 import org.w3c.dom.NodeList;
56 import org.xml.sax.ErrorHandler;
57 import org.xml.sax.InputSource;
58 import org.xml.sax.SAXException;
59 import org.xml.sax.SAXParseException;
61 public class AdapterRegistry2 {
63 public static final String ADAPTERS_FILE = "adapters.xml";
65 public static final String ADAPTERS = "adapters";
66 public static final String ADAPTER = "adapter";
67 public static final String TARGET = "target";
68 public static final String BASE_TYPE = "baseType";
69 public static final String TYPE = "type";
70 public static final String RESOURCE = "resource";
71 public static final String URI = "uri";
72 public static final String INTERFACE = "interface";
73 public static final String CLASS = "class";
74 public static final String ADAPTER_CLASS = "adapterClass";
75 public static final String CONTEXT_CLASS = "contextClass";
76 public static final String INSTALLER = "installer";
77 public static final String CONSTRUCTOR = "constructor";
79 static private AdapterRegistry2 instance = new AdapterRegistry2();
80 Collection<AdapterInstaller> installers = new ArrayList<AdapterInstaller>();
81 Map<AdapterInstaller, String> installerSources = new HashMap<AdapterInstaller, String>();
82 Collection<Exception> exceptions = new ArrayList<Exception>();
84 public static AdapterRegistry2 getInstance() {
88 private void addInstaller(AdapterInstaller installer, String sourceDesc) {
89 installers.add(installer);
90 installerSources.put(installer, sourceDesc);
93 private void handleException(Exception e, String fileName) {
94 System.err.println("At " + fileName);
98 private void handleException(Exception e, AdapterInstaller installer) {
99 String desc = installerSources.get(installer);
101 System.err.println("At " + desc);
105 private void handleAdaptersDocument(Loader b, Document doc, String fileName) {
107 Node node = doc.getDocumentElement();
108 if(node.getNodeName().equals(ADAPTERS)) {
109 NodeList nodeList = node.getChildNodes();
110 for(int i=0;i<nodeList.getLength();++i) {
111 Node n = nodeList.item(i);
112 if(n.getNodeName().equals(TARGET))
113 handleTarget(b, n, fileName);
114 else if(n.getNodeName().equals(INSTALLER))
115 handleInstaller(b, n, fileName);
118 } catch (Exception e) {
119 handleException(e, fileName);
123 private void handleTarget(Loader b, Node node, String fileName) {
125 Class<?> interface_ =
126 b.loadClass(node.getAttributes().getNamedItem("interface")
128 NodeList nodeList = node.getChildNodes();
129 for(int i=0;i<nodeList.getLength();++i) {
130 Node n = nodeList.item(i);
131 String nodeName = n.getNodeName();
132 if(nodeName.equals(BASE_TYPE))
133 handleBaseType(b, interface_, n, fileName);
134 else if(nodeName.equals(TYPE))
135 handleType(b, interface_, n, fileName);
136 else if(nodeName.equals(ADAPTER))
137 handleAdapter(b, interface_, n, fileName);
138 else if(nodeName.equals(RESOURCE))
139 handleResource(b, interface_, n, fileName);
141 } catch (Exception e) {
142 handleException(e, fileName);
146 private void handleInstaller(Loader b, Node node, String fileName) {
148 AdapterInstaller installer =
149 ((Class<?>)b.loadClass(node.getAttributes().getNamedItem("class").getNodeValue()))
150 .asSubclass(AdapterInstaller.class).newInstance();
151 addInstaller(installer, fileName);
152 } catch (Exception e) {
153 handleException(e, fileName);
157 private <T> void handleResource(final Loader b, final Class<T> interface_, final Node node, String fileName) {
159 NamedNodeMap attr = node.getAttributes();
160 final String uri = attr.getNamedItem(URI).getNodeValue();
161 final String className = attr.getNamedItem(CLASS).getNodeValue();
162 Node constructorNode = attr.getNamedItem(CONSTRUCTOR);
163 final String constructor = constructorNode == null ? null : constructorNode.getNodeValue();
164 // System.out.println("AdapterRegistry2.handleResource: " + b + " " + uri + " " + interface_);
167 new AdapterInstaller() {
170 public void install(ReadGraph g, AdaptionService service) throws Exception {
171 Class<? extends T> clazz = b.loadClass(className).asSubclass(interface_);
172 List<IDynamicAdapter2> parameters = readParameters(g, node, b);
173 IDynamicAdapter2[] parameterArray =
174 parameters.toArray(new IDynamicAdapter2[parameters.size()]);
175 Resource r = g.getResource(uri);
176 service.addInstanceAdapter(
180 ? new ReflectionAdapter2<T>(clazz, parameterArray)
181 : new StaticMethodAdapter<T>(clazz, constructor, parameterArray));
185 } catch (Exception e) {
186 handleException(e, fileName);
190 private <T> void handleType(final Loader b, final Class<T> interface_, final Node node, String fileName) {
192 final NamedNodeMap attr = node.getAttributes();
193 final String uri = attr.getNamedItem(URI).getNodeValue();
194 Node constructorNode = attr.getNamedItem(CONSTRUCTOR);
195 final String constructor = constructorNode == null ? null : constructorNode.getNodeValue();
196 //System.out.println("AdapterRegistry2.handleType: " + b + " " + uri + " " + interface_);
198 new AdapterInstaller() {
201 public void install(ReadGraph g, AdaptionService service) throws Exception {
203 Class<? extends T> clazz =
204 ((Class<?>)b.loadClass(attr.getNamedItem(CLASS).getNodeValue()))
205 .asSubclass(interface_);
206 List<IDynamicAdapter2> parameters = readParameters(g, node, b);
207 IDynamicAdapter2[] parameterArray =
208 parameters.toArray(new IDynamicAdapter2[parameters.size()]);
213 ? new ReflectionAdapter2<T>(clazz, parameterArray)
214 : new StaticMethodAdapter<T>(clazz, constructor, parameterArray));
216 System.err.println("Failed to adapt "+interface_.getName());
218 } catch(RuntimeException t) {
219 System.err.println("Failed to adapt "+interface_.getName());
225 } catch (Exception e) {
227 handleException(e, fileName);
231 private List<IDynamicAdapter2> readParameters(ReadGraph g, Node node, Loader b) throws DatabaseException, DOMException, ClassNotFoundException {
232 NodeList nodeList = node.getChildNodes();
233 ArrayList<IDynamicAdapter2> parameters = new ArrayList<IDynamicAdapter2>();
234 for(int i=0;i<nodeList.getLength();++i) {
235 Node n = nodeList.item(i);
236 if(n.getNodeType() == Node.ELEMENT_NODE) {
237 NamedNodeMap attr = n.getAttributes();
238 IDynamicAdapter2 da = null;
239 if(n.getNodeName().equals("this"))
240 da = new ThisResource2();
241 else if(n.getNodeName().equals("graph"))
242 da = new GraphObject2();
243 else if(n.getNodeName().equals("bundle")) {
244 String bundleId = null;
245 Node fc = n.getFirstChild();
247 bundleId = fc.getNodeValue();
248 if (bundleId == null) {
249 da = new ConstantAdapter(Bundle.class, b.getBundle());
251 Bundle ob = Platform.getBundle(bundleId);
253 da = new ConstantAdapter(Bundle.class, ob);
255 throw new DOMException(DOMException.NOT_FOUND_ERR, "bundle '" + bundleId + "' not found");
258 } else if(n.getNodeName().equals("related"))
259 da = new RelatedResources2(
260 g.getResource(attr.getNamedItem("uri").getNodeValue()));
261 else if(n.getNodeName().equals("orderedSet"))
262 da = new OrderedSetResources2(
263 g.getResource(attr.getNamedItem("uri").getNodeValue()));
264 else if(n.getNodeName().equals("single"))
265 da = new SingleRelatedResource2(
266 g.getResource(attr.getNamedItem("uri").getNodeValue()));
267 else if(n.getNodeName().equals("atMostOne"))
268 da = new AtMostOneRelatedResource2(
269 g.getResource(attr.getNamedItem("uri").getNodeValue()));
270 else if(n.getNodeName().equals("string"))
271 da = new ConstantAdapter(String.class, n.getFirstChild().getNodeValue());
273 Node toNode = attr.getNamedItem("to");
275 String to = toNode.getNodeValue();
276 da = new AdaptingDynamicAdapter2(da, b.loadClass(to));
285 private <T> void handleAdapter(final Loader b, final Class<T> interface_, Node node, String fileName) {
287 NamedNodeMap attr = node.getAttributes();
288 final String uri = attr.getNamedItem(URI).getNodeValue();
289 final String clazz = attr.getNamedItem(ADAPTER_CLASS).getNodeValue();
291 Node contextNode = attr.getNamedItem(CONTEXT_CLASS);
292 final Class<?> contextClass = contextNode != null ? b.loadClass(contextNode.getNodeValue()) : Resource.class;
294 //System.out.println("AdapterRegistry2.handleAdapter: " + b + " " + uri + " " + interface_ + ", class=" + clazz);
296 new AdapterInstaller() {
298 @SuppressWarnings("unchecked")
300 public void install(ReadGraph g, AdaptionService service) throws Exception {
305 ((Class<?>)b.loadClass(clazz))
306 .asSubclass(Adapter.class).newInstance());
310 } catch (Exception e) {
311 handleException(e, fileName);
315 private <T> void handleBaseType(Loader b, final Class<T> interface_, Node node, String fileName) {
317 NamedNodeMap attr = node.getAttributes();
318 final String uri = attr.getNamedItem(URI).getNodeValue();
320 new AdapterInstaller() {
323 public void install(ReadGraph g, AdaptionService service) throws Exception {
324 service.declareAdapter(
330 } catch (Exception e) {
331 handleException(e, fileName);
335 public void updateAdaptionService(Session s, final AdaptionService service) throws DatabaseException {
336 s.syncRequest(new ReadRequest() {
338 public void run(ReadGraph g) {
339 for(AdapterInstaller t : installers) {
341 t.install(g, service);
342 } catch (Exception e) {
343 AdapterRegistry2.this.handleException(e, t);
350 public void initialize(ClassLoader b, String schemaURL, File[] files) {
354 DocumentBuilderFactory factory =
355 DocumentBuilderFactory.newInstance();
357 if(schemaURL != null && validateAgainstSchema()) {
359 factory.setValidating(true);
360 factory.setAttribute(
361 "http://java.sun.com/xml/jaxp/properties/schemaLanguage",
362 "http://www.w3.org/2001/XMLSchema");
363 factory.setAttribute(
364 "http://java.sun.com/xml/jaxp/properties/schemaSource", schemaURL);
368 // TODO Listen bundles (install/uninstall)
369 if (exceptions.isEmpty())
370 for (final File f : files) {
371 // String fileName = new Path(b.getLocation()).append(file.getPath()).toString();
373 DocumentBuilder builder = factory.newDocumentBuilder();
374 builder.setErrorHandler(new ErrorHandler() {
377 public void error(SAXParseException exception)
378 throws SAXException {
379 // TODO Put this error somewhere
380 System.err.println("Parse error at " + f.getAbsolutePath() +
381 // + b.getSymbolicName() + "/adapters.xml" +
382 " line " + exception.getLineNumber() +
383 " column " + exception.getColumnNumber() + ":");
384 System.err.println(exception.getMessage());
388 public void fatalError(SAXParseException exception)
389 throws SAXException {
394 public void warning(SAXParseException exception)
395 throws SAXException {
400 //System.out.println("bundle=" + b.getSymbolicName());
401 Document doc = builder.parse(f);
402 handleAdaptersDocument(loader(b), doc, f.getAbsolutePath());
403 } catch (Exception e) {
404 handleException(e, f.getAbsolutePath());
408 } catch (Exception e) {
409 handleException(e, "(no file name available)");
414 private boolean validateAgainstSchema() {
415 return Platform.inDevelopmentMode();
418 public void initialize(BundleContext context) {
422 DocumentBuilderFactory factory =
423 DocumentBuilderFactory.newInstance();
425 if (validateAgainstSchema()) {
426 factory.setValidating(true);
427 factory.setAttribute(
428 "http://java.sun.com/xml/jaxp/properties/schemaLanguage",
429 "http://www.w3.org/2001/XMLSchema");
430 factory.setAttribute(
431 "http://java.sun.com/xml/jaxp/properties/schemaSource",
432 context.getBundle().getResource("adapters.xsd").toString());
435 // TODO Listen bundles (install/uninstall)
436 if (exceptions.isEmpty())
437 for (final Bundle b : context.getBundles()) {
438 URL file = b.getEntry(ADAPTERS_FILE);
440 String fileName = new Path(b.getLocation()).append(file.getPath()).toString();
442 DocumentBuilder builder = factory.newDocumentBuilder();
443 builder.setErrorHandler(new ErrorHandler() {
446 public void error(SAXParseException exception)
447 throws SAXException {
448 // TODO Put this error somewhere
449 System.err.println("Parse error at "
450 + b.getSymbolicName() + "/adapters.xml" +
451 " line " + exception.getLineNumber() +
452 " column " + exception.getColumnNumber() + ":");
453 System.err.println(exception.getMessage());
457 public void fatalError(SAXParseException exception)
458 throws SAXException {
463 public void warning(SAXParseException exception)
464 throws SAXException {
470 //System.out.println("bundle=" + b.getSymbolicName());
471 String text = FileUtils.getContents(file);
472 text = OntologyVersions.getInstance().currentVersion(text);
473 StringReader reader = new StringReader( text );
474 InputSource inputSource = new InputSource( reader );
475 Document doc = builder.parse( inputSource );
477 handleAdaptersDocument(loader(b), doc, fileName);
478 } catch (Exception e) {
479 handleException(e, fileName);
484 } catch (Exception e) {
485 handleException(e, "(no file name available)");
490 Class<?> loadClass(String name) throws ClassNotFoundException ;
494 private Loader loader(final Bundle b) {
495 return new Loader() {
498 public Class<?> loadClass(String name) throws ClassNotFoundException {
499 return b.loadClass(name);
503 public Bundle getBundle() {
510 private Loader loader(final ClassLoader b) {
511 return new Loader() {
514 public Class<?> loadClass(String name) throws ClassNotFoundException {
515 return b.loadClass(name);
519 public Bundle getBundle() {