-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.db.services.adaption;\r
-\r
-import gnu.trove.map.hash.THashMap;\r
-import gnu.trove.procedure.TObjectObjectProcedure;\r
-import gnu.trove.set.hash.THashSet;\r
-\r
-import org.simantics.db.AsyncReadGraph;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.adaption.Adapter;\r
-import org.simantics.db.adaption.AdaptionService;\r
-import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;\r
-import org.simantics.db.common.procedure.single.SyncReadProcedure;\r
-import org.simantics.db.common.request.BinaryRead;\r
-import org.simantics.db.common.request.ReadRequest;\r
-import org.simantics.db.common.request.TernaryRead;\r
-import org.simantics.db.common.uri.ResourceToURI;\r
-import org.simantics.db.common.utils.NameUtils;\r
-import org.simantics.db.exception.AdaptionException;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.exception.ServiceException;\r
-import org.simantics.db.exception.ValidationException;\r
-import org.simantics.db.procedure.AsyncProcedure;\r
-import org.simantics.db.request.AsyncRead;\r
-import org.simantics.db.request.Read;\r
-import org.simantics.layer0.Layer0;\r
-import org.simantics.utils.datastructures.Pair;\r
-\r
-public class AdaptionService2 implements AdaptionService {\r
-\r
- THashMap<Pair<Class<?>,Class<?>>, AdapterDeclaration<?>> adapters =\r
- new THashMap<Pair<Class<?>,Class<?>>, AdapterDeclaration<?>>();\r
-\r
- /**\r
- * Contains all adapter declarations and definitions for one class (clazz).\r
- */\r
- static class AdapterDeclaration<T> {\r
- Class<T> clazz;\r
- THashMap<Resource, Adapter<T,?>> typeAdapters =\r
- new THashMap<Resource, Adapter<T,?>>();\r
- THashMap<Resource, Adapter<T,?>> instanceAdapters =\r
- new THashMap<Resource, Adapter<T,?>>();\r
- THashSet<Resource> baseTypes = new THashSet<Resource>();\r
-\r
- String getDescription(final ReadGraph g) {\r
- final StringBuilder b = new StringBuilder();\r
- b.append("The following adapters have been defined for ");\r
- b.append(clazz.getCanonicalName());\r
- b.append("\n");\r
- typeAdapters.forEachEntry(new TObjectObjectProcedure<Resource, Adapter<T,?>>() {\r
-\r
- @Override\r
- public boolean execute(Resource arg0, Adapter<T,?> arg1) {\r
- b.append(" type ");\r
- try {\r
- b.append(g.syncRequest(new ResourceToURI(arg0)));\r
- } catch (DatabaseException e) {\r
- e.printStackTrace();\r
- }\r
- b.append(" : ");\r
- b.append(arg1);\r
- b.append('\n');\r
- return true;\r
- }\r
-\r
- });\r
-\r
- synchronized (this) {\r
- instanceAdapters.forEachEntry(new TObjectObjectProcedure<Resource, Adapter<T,?>>() {\r
-\r
- @Override\r
- public boolean execute(Resource arg0, Adapter<T,?> arg1) {\r
- b.append(" resource ");\r
- try {\r
- b.append(g.syncRequest(new ResourceToURI(arg0)));\r
- } catch (DatabaseException e) {\r
- e.printStackTrace();\r
- }\r
- b.append(" : ");\r
- b.append(arg1);\r
- b.append('\n');\r
- return true;\r
- }\r
-\r
- });\r
- }\r
- return b.toString();\r
- }\r
-\r
- public AdapterDeclaration(Class<T> clazz) {\r
- this.clazz = clazz;\r
- }\r
-\r
- static class AdapterResult<T,C> {\r
- Adapter<T,C> adapter;\r
- Resource type;\r
-\r
- public AdapterResult(Adapter<T,C> adapter, Resource type) {\r
- this.adapter = adapter;\r
- this.type = type;\r
- }\r
- }\r
-\r
- /**\r
- * The query returns the adapter inherited by the parameter type.\r
- * The query is used only in the case, the type itself does not have\r
- * an adapter. The second component of the result contains the type\r
- * that originally contributed the adapter.\r
- */\r
- static class GetInheritedAdapter<T,C> extends BinaryRead<Resource, AdapterDeclaration<T>, AdapterResult<T,C>> {\r
-\r
- public GetInheritedAdapter(Resource type, AdapterDeclaration<T> decl) {\r
- super(type, decl);\r
- }\r
-\r
- AdapterDeclaration<T> getDeclaration() {\r
- return parameter2;\r
- }\r
-\r
- @Override\r
- public String toString() {\r
- return "GetInheritedAdapter|" + parameter + "|" + parameter2;\r
- }\r
-\r
- @SuppressWarnings("unchecked")\r
- @Override\r
- public AdapterResult<T,C> perform(ReadGraph g) throws DatabaseException {\r
- Layer0 b = Layer0.getInstance(g);\r
- AdapterResult<T,C> result = null;\r
- for(Resource supertype : g.getObjects(parameter, b.Inherits)) {\r
- Adapter<T,C> adapter = (Adapter<T,C>)parameter2.typeAdapters.get(supertype);\r
- if(adapter != null) {\r
- if(result == null)\r
- result = new AdapterResult<T,C>(adapter, supertype);\r
- else if(!result.type.equals(supertype) &&\r
- !g.isInheritedFrom(result.type, supertype)) {\r
- if(g.isInheritedFrom(supertype, result.type))\r
- result = new AdapterResult<T,C>(adapter, supertype);\r
- else throw new AdaptionException("Type " +\r
- safeName(g, parameter) + " inherits conflicting adapters from "\r
- + safeName(g, supertype) + " and " + safeName(g, result.type));\r
- }\r
- }\r
- else {\r
- AdapterResult<T,C> temp =\r
- g.syncRequest(new GetInheritedAdapter<T, C>(supertype, parameter2), TransientCacheAsyncListener.<AdapterResult<T,C>>instance());\r
- if(temp != null) {\r
- if(result == null)\r
- result = temp;\r
- else if(!result.type.equals(temp.type) &&\r
- !g.isInheritedFrom(result.type, temp.type)) {\r
- if(g.isInheritedFrom(temp.type, result.type))\r
- result = temp;\r
- else throw new AdaptionException("Type " +\r
- safeName(g, parameter) + " inherits conflicting adapters from "\r
- + safeName(g, temp.type) + " and " + safeName(g, result.type));\r
- }\r
- }\r
- }\r
- }\r
- return result;\r
- }\r
-\r
- }\r
-\r
- <C> void inheritedAdapter(AsyncReadGraph graph, Resource type, AsyncProcedure<AdapterResult<T,C>> procedure) {\r
- graph.asyncRequest(new GetInheritedAdapter<T, C>(type, this), procedure);\r
- }\r
-\r
- Adapter<T,?> directAdapter(Resource r) {\r
- Adapter<T,?> ret;\r
- synchronized (this) {\r
- ret = instanceAdapters.get(r);\r
- }\r
- return ret;\r
- }\r
-\r
- static class FindAdapter<T,C> extends BinaryRead<Resource, AdapterDeclaration<T>, Adapter<T,C>> {\r
-\r
- public FindAdapter(Resource resource, AdapterDeclaration<T> decl) {\r
- super(resource, decl);\r
- }\r
- \r
- @SuppressWarnings("unchecked")\r
- Adapter<T,C> findAdapter(Resource r, ReadGraph g) throws DatabaseException {\r
-\r
- {\r
- Adapter<T,C> adapter;\r
- synchronized (this) {\r
- adapter = (Adapter<T,C>)parameter2.instanceAdapters.get(r);\r
- }\r
- if(adapter != null)\r
- return adapter;\r
- }\r
-\r
- Layer0 b = Layer0.getInstance(g);\r
-\r
- /*\r
- * Try to find adapter from immediate types\r
- */\r
- AdapterResult<T,C> adapterResult = null;\r
- for(Resource t : g.getObjects(r, b.InstanceOf)) {\r
- Adapter<T,C> adapter = (Adapter<T,C>)parameter2.typeAdapters.get(t);\r
- if(adapter != null) {\r
- if(adapterResult == null)\r
- adapterResult = new AdapterResult<T,C>(adapter, t);\r
- else if(!adapterResult.type.equals(t) &&\r
- !g.isInheritedFrom(adapterResult.type, t)) {\r
- if(g.isInheritedFrom(t, adapterResult.type))\r
- adapterResult = new AdapterResult<T,C>(adapter, t);\r
- else throw new AdaptionException("Resource " +\r
- safeName(g, r) + " has conflicting " + parameter2.clazz + "-adapters from "\r
- + safeName(g, t) + " and " + safeName(g, adapterResult.type)\r
- );\r
- }\r
- }\r
- else {\r
- AdapterResult<T,C> temp =\r
- g.syncRequest(new GetInheritedAdapter<T, C>(t, parameter2), TransientCacheAsyncListener.<AdapterResult<T,C>>instance());\r
- if(temp != null) {\r
- if(adapterResult == null)\r
- adapterResult = temp;\r
- else if(!adapterResult.type.equals(temp.type) &&\r
- !g.isInheritedFrom(adapterResult.type, temp.type)) {\r
- if(g.isInheritedFrom(temp.type, adapterResult.type))\r
- adapterResult = temp;\r
- else throw new AdaptionException("Resource " +\r
- safeName(g, r) + " has conflicting " + parameter2.clazz + "-adapters from "\r
- + safeName(g, temp.type) + " and " + safeName(g, adapterResult.type)\r
- );\r
- }\r
- }\r
- }\r
- }\r
-\r
- if(adapterResult != null)\r
- return adapterResult.adapter;\r
-\r
- for(Resource t : g.getObjects(r, b.Inherits)) {\r
- Adapter<T,C> adapter = findAdapter(t, g);\r
- if(adapter != null)\r
- return adapter;\r
- }\r
-\r
- for(Resource t : g.getObjects(r, b.SubrelationOf)) {\r
- Adapter<T,C> adapter = findAdapter(t, g);\r
- if(adapter != null)\r
- return adapter;\r
- }\r
-\r
- return null;\r
-\r
- }\r
-\r
- \r
- @Override\r
- public Adapter<T,C> perform(ReadGraph g) throws DatabaseException {\r
- return (Adapter<T, C>)findAdapter(parameter, g);\r
- }\r
- \r
- }\r
- \r
- /**\r
- * The query returns either an adapter or adapted for the given\r
- * resource. It is assumed that the resource itself does not\r
- * have adapted.\r
- */\r
- class Adapt<C> implements Read<T> {\r
-\r
- Resource resource;\r
- C context;\r
-\r
- public Adapt(Resource resource, C context) {\r
- this.resource = resource;\r
- this.context = context;\r
- }\r
-\r
- AdapterDeclaration<T> getDeclaration() {\r
- return AdapterDeclaration.this;\r
- }\r
-\r
- @SuppressWarnings("unchecked")\r
- Adapter<T,C> findAdapter(Resource r, ReadGraph g) throws DatabaseException {\r
-\r
- {\r
- Adapter<T,C> adapter;\r
- synchronized (this) {\r
- adapter = (Adapter<T,C>)instanceAdapters.get(r);\r
- }\r
- if(adapter != null)\r
- return adapter;\r
- }\r
-\r
- Layer0 b = Layer0.getInstance(g);\r
-\r
- /*\r
- * Try to find adapter from immediate types\r
- */\r
- AdapterResult<T,C> adapterResult = null;\r
- for(Resource t : g.getObjects(r, b.InstanceOf)) {\r
- Adapter<T,C> adapter = (Adapter<T,C>)typeAdapters.get(t);\r
- if(adapter != null) {\r
- if(adapterResult == null)\r
- adapterResult = new AdapterResult<T,C>(adapter, t);\r
- else if(!adapterResult.type.equals(t) &&\r
- !g.isInheritedFrom(adapterResult.type, t)) {\r
- if(g.isInheritedFrom(t, adapterResult.type))\r
- adapterResult = new AdapterResult<T,C>(adapter, t);\r
- else throw new AdaptionException("Resource " +\r
- safeName(g, r) + " has conflicting " + clazz + "-adapters from "\r
- + safeName(g, t) + " and " + safeName(g, adapterResult.type)\r
- );\r
- }\r
- }\r
- else {\r
- AdapterResult<T,C> temp =\r
- g.syncRequest(new GetInheritedAdapter<T, C>(t, AdapterDeclaration.this));\r
- if(temp != null) {\r
- if(adapterResult == null)\r
- adapterResult = temp;\r
- else if(!adapterResult.type.equals(temp.type) &&\r
- !g.isInheritedFrom(adapterResult.type, temp.type)) {\r
- if(g.isInheritedFrom(temp.type, adapterResult.type))\r
- adapterResult = temp;\r
- else throw new AdaptionException("Resource " +\r
- safeName(g, r) + " has conflicting " + clazz + "-adapters from "\r
- + safeName(g, temp.type) + " and " + safeName(g, adapterResult.type)\r
- );\r
- }\r
- }\r
- }\r
- }\r
-\r
- if(adapterResult != null)\r
- return adapterResult.adapter;\r
-\r
- for(Resource t : g.getObjects(r, b.Inherits)) {\r
- Adapter<T,C> adapter = findAdapter(t, g);\r
- if(adapter != null)\r
- return adapter;\r
- }\r
-\r
- for(Resource t : g.getObjects(r, b.SubrelationOf)) {\r
- Adapter<T,C> adapter = findAdapter(t, g);\r
- if(adapter != null)\r
- return adapter;\r
- }\r
-\r
- return null;\r
-\r
- }\r
-\r
- @Override\r
- public T perform(ReadGraph g) throws DatabaseException {\r
-\r
- final Adapter<T,C> adapter = (Adapter<T, C>)findAdapter(resource, g);\r
- if(adapter == null) return null;\r
- else return g.syncRequest(new AsyncRead<T>() {\r
-\r
- @Override\r
- public void perform(AsyncReadGraph graph, AsyncProcedure<T> procedure) {\r
-// System.out.println("adapter=" + adapter);\r
- adapter.adapt(graph, resource, context, procedure);\r
- }\r
-\r
- @Override\r
- public int threadHash() {\r
- return hashCode();\r
- }\r
-\r
- @Override\r
- public int getFlags() {\r
- return 0;\r
- }\r
-\r
- });\r
-\r
- }\r
-\r
- @SuppressWarnings("rawtypes")\r
- @Override\r
- public boolean equals(Object other) {\r
-\r
- if (this == other)\r
- return true;\r
- else if (other == null)\r
- return false;\r
- else if (other.getClass() != Adapt.class)\r
- return false;\r
-\r
- return ((Adapt)other).resource.equals(resource)\r
- && ((Adapt)other).context.equals(context)\r
- && ((Adapt)other).getDeclaration()==getDeclaration();\r
-\r
- }\r
-\r
- @Override\r
- public int hashCode() {\r
- return resource.hashCode() + 31*((getClass().hashCode() + 41*(context.hashCode()) + \r
- 71*getDeclaration().hashCode()));\r
- }\r
-\r
- }\r
-\r
-// void adapt2(AsyncReadGraph graph, Resource r, AsyncProcedure<T> procedure) {\r
-// graph.asyncRequest(new Adapt(r), procedure);\r
-// }\r
-\r
- <C> Adapter<T,C> findAdapter(ReadGraph g, Resource r, boolean possible) throws DatabaseException {\r
-\r
- Adapter<T,C> result = g.syncRequest(new FindAdapter<T,C>(r, AdapterDeclaration.this));\r
- if(result != null) return result;\r
-\r
- if (possible)\r
- return null;\r
-\r
- /*\r
- * We couldn't adapt the resource. We analyze the situation little for\r
- * better error message.\r
- */\r
- for(Resource dt : baseTypes) {\r
- if(g.isInstanceOf(r, dt)) {\r
- throw new AdaptionException("Couldn't find a " + clazz + "-adapter for resource " +\r
- safeName(g, r) + " although it is instance of " +\r
- safeName(g, dt) + "\n" +\r
- getDescription(g));\r
- }\r
- }\r
- throw new AdaptionException("Couldn't find a " + clazz + "-adapter for resource " +\r
- safeName(g, r) +\r
- ". This is because the resource is not instance of any type which the adapter is declared to.\n" +\r
- getDescription(g));\r
-\r
- }\r
- \r
- <C> T adapt(ReadGraph g, Resource r, C context, boolean possible) throws DatabaseException {\r
-\r
- T result = g.syncRequest(new Adapt<C>(r,context));\r
- if(result != null) return result;\r
-\r
- if (possible)\r
- return null;\r
-\r
- /*\r
- * We couldn't adapt the resource. We analyze the situation little for\r
- * better error message.\r
- */\r
- for(Resource dt : baseTypes) {\r
- if(g.isInstanceOf(r, dt)) {\r
- throw new AdaptionException("Couldn't find a " + clazz + "-adapter for resource " +\r
- safeName(g, r) + " although it is instance of " +\r
- safeName(g, dt) + "\n" +\r
- getDescription(g));\r
- }\r
- }\r
- throw new AdaptionException("Couldn't find a " + clazz + "-adapter for resource " +\r
- safeName(g, r) +\r
- ". This is because the resource is not instance of any type which the adapter is declared to.\n" +\r
- getDescription(g));\r
-\r
- }\r
-\r
- T adaptNew(ReadGraph g, final Resource r, boolean possible) throws DatabaseException {\r
-\r
- T result = new Adapt<Resource>(r,r).perform(g);\r
- if (result != null)\r
- return result;\r
-\r
- if (possible)\r
- return null;\r
-\r
- for(Resource dt : baseTypes) {\r
- if(g.isInstanceOf(r, dt)) {\r
- throw new AdaptionException("Couldn't find a " + clazz + "-adapter for resource " +\r
- safeName(g, r) + " although it is instance of " +\r
- safeName(g, dt) + "\n" +\r
- getDescription(g));\r
- }\r
- }\r
- throw new AdaptionException("Couldn't find a " + clazz + "-adapter for resource " +\r
- safeName(g, r) +\r
- ". This is because the resource is not instance of any type which the adapter is declared to.\n" +\r
- getDescription(g));\r
-\r
- }\r
-\r
- }\r
-\r
- private <T> AdapterDeclaration<T> getDeclaration(Class<T> targetClass, Class<?> contextClass) {\r
- Pair<Class<?>,Class<?>> key = new Pair<Class<?>,Class<?>>(targetClass, contextClass);\r
- @SuppressWarnings("unchecked")\r
- AdapterDeclaration<T> decl =\r
- (AdapterDeclaration<T>)adapters.get(key);\r
- if(decl == null) {\r
- decl = new AdapterDeclaration<T>(targetClass);\r
- adapters.put(key, decl);\r
- }\r
- return decl;\r
- }\r
-\r
- public <T,C> void getAdapter(AsyncReadGraph graph, final Resource r, final Class<C> contextClass, final Class<T> targetClass, final boolean possible, final AsyncProcedure<Adapter<T,C>> procedure) {\r
- \r
- final Pair<Class<T>, Class<?>> key = new Pair<Class<T>, Class<?>>(targetClass, contextClass); \r
- @SuppressWarnings("unchecked")\r
- final AdapterDeclaration<T> decl = (AdapterDeclaration<T>)adapters.get(key);\r
- if(decl == null) {\r
-\r
- if(possible) {\r
- procedure.execute(graph, null);\r
- } else {\r
- procedure.exception(graph, new AdaptionException("There are no adapters declared or defined for class " + targetClass + "."));\r
- }\r
-\r
- } else {\r
-\r
- @SuppressWarnings("unchecked")\r
- final Adapter<T,C> adapter = (Adapter<T,C>)decl.directAdapter(r);\r
- if(adapter != null) {\r
- procedure.execute(graph, adapter);\r
- } else {\r
- graph.forPossibleObject(r, graph.getService(Layer0.class).InstanceOf, new AsyncProcedure<Resource>() {\r
-\r
- @Override\r
- public void exception(AsyncReadGraph graph, Throwable throwable) {\r
- procedure.exception(graph, new AdaptionException("Problems in reading types for resource. ", throwable));\r
- }\r
-\r
- @Override\r
- public void execute(AsyncReadGraph graph, final Resource singleType) {\r
- if(singleType != null) {\r
- getSingleTypeAdapter(graph, decl, key, r, singleType, possible, procedure);\r
- } else {\r
- getSingleSuperTypeAdapter(graph, decl, key, r, r, possible, procedure);\r
- }\r
- }\r
-\r
- });\r
- }\r
-\r
- }\r
- \r
- }\r
- \r
- @Override\r
- public <T,C> void adapt(AsyncReadGraph graph, final Resource r, final C context, Class<C> contextClass, Class<T> targetClass, final boolean possible, final AsyncProcedure<T> procedure) {\r
-\r
- getAdapter(graph, r, contextClass, targetClass, possible, new AsyncProcedure<Adapter<T,C>>() {\r
-\r
- @Override\r
- public void execute(AsyncReadGraph graph, Adapter<T, C> result) {\r
- if(result == null) {\r
- if(possible) {\r
- procedure.execute(graph, null);\r
- } else {\r
- procedure.exception(graph, new AdaptionException("Internal error. getAdapter returned null and possible was false."));\r
- }\r
- } else {\r
- result.adapt(graph, r, context, procedure);\r
- }\r
- }\r
-\r
- @Override\r
- public void exception(AsyncReadGraph graph, Throwable throwable) {\r
- procedure.exception(graph, throwable);\r
- }\r
- \r
- });\r
-\r
- }\r
- \r
- @Override\r
- public <T, C> T adapt(ReadGraph g, Resource r, C context, Class<C> contextClass, Class<T> targetClass, boolean possible) throws DatabaseException {\r
-\r
- Adapter<T,C> adapter = getAdapter(g, r, context, contextClass, targetClass, possible);\r
- \r
- SyncReadProcedure<T> procedure = new SyncReadProcedure<T>();\r
- adapter.adapt(g, r, context, procedure);\r
- procedure.checkAndThrow();\r
- return procedure.result;\r
- \r
- }\r
- \r
- private <T, C> Adapter<T,C> getAdapter(ReadGraph g, Resource r, C context, Class<C> contextClass, Class<T> targetClass, boolean possible) throws DatabaseException {\r
- \r
- final Pair<Class<T>, Class<?>> key = new Pair<Class<T>, Class<?>>(targetClass, contextClass); \r
- @SuppressWarnings("unchecked")\r
- final AdapterDeclaration<T> decl = (AdapterDeclaration<T>)adapters.get(key);\r
- if(decl == null) {\r
-\r
- if(possible) return null;\r
- else throw new AdaptionException("There are no adapters declared or defined for class " + targetClass + ".");\r
-\r
- } else {\r
-\r
- @SuppressWarnings("unchecked")\r
- final Adapter<T,C> adapter = (Adapter<T,C>)decl.directAdapter(r);\r
- if(adapter != null) return adapter;\r
- \r
- Layer0 L0 = Layer0.getInstance(g);\r
- Resource singleType = g.getPossibleObject(r, L0.InstanceOf);\r
- if(singleType != null) {\r
- return getSingleTypeAdapter(g, decl, key, r, singleType, possible);\r
- } else {\r
- return getSingleSuperTypeAdapter(g, decl, key, r, r, possible);\r
- }\r
-\r
- } \r
- \r
- }\r
-\r
- private static class SingleTypeAdapter<T, C> extends TernaryRead<Pair<Class<T>, Class<?>>, Resource, Boolean, Adapter<T,C>> {\r
-\r
- final private AdapterDeclaration<T> decl;\r
- \r
- SingleTypeAdapter(AdapterDeclaration<T> decl, Pair<Class<T>, Class<?>> key, Resource instance, Boolean possible) {\r
- super(key, instance, possible);\r
- this.decl = decl;\r
- }\r
- \r
- @Override\r
- public Adapter<T,C> perform(ReadGraph graph) throws DatabaseException {\r
- return decl.findAdapter(graph, parameter2, parameter3);\r
- }\r
-\r
- }\r
- \r
- private <T,C> void getSingleTypeAdapter(AsyncReadGraph graph, final AdapterDeclaration<T> decl, final Pair<Class<T>, Class<?>> key, final Resource instance, final Resource type, final boolean possible, final AsyncProcedure<Adapter<T,C>> procedure) {\r
-\r
- @SuppressWarnings("unchecked")\r
- Adapter<T,C> adapter = (Adapter<T,C>)decl.typeAdapters.get(type);\r
- if(adapter != null) {\r
- procedure.execute(graph, adapter);\r
- } else {\r
- graph.forPossibleObject(type, graph.getService(Layer0.class).Inherits, new AsyncProcedure<Resource>() {\r
-\r
- @Override\r
- public void exception(AsyncReadGraph graph, Throwable throwable) {\r
- procedure.exception(graph, new AdaptionException("Problems in reading super types for resource. ", throwable));\r
- }\r
-\r
- @Override\r
- public void execute(AsyncReadGraph graph, Resource singleSuperType) {\r
-\r
- if(singleSuperType != null) {\r
- getSingleTypeAdapter(graph, decl, key, instance, singleSuperType, possible, procedure);\r
- } else {\r
- graph.asyncRequest(new SingleTypeAdapter<T,C>(decl, key, instance, possible), procedure);\r
- }\r
-\r
- }\r
-\r
- });\r
-\r
-\r
- }\r
-\r
- }\r
- \r
- private <T,C> Adapter<T,C> getSingleTypeAdapter(ReadGraph graph, final AdapterDeclaration<T> decl, final Pair<Class<T>, Class<?>> key, final Resource instance, final Resource type, final boolean possible) throws DatabaseException {\r
-\r
- @SuppressWarnings("unchecked")\r
- Adapter<T,C> adapter = (Adapter<T,C>)decl.typeAdapters.get(type);\r
- if(adapter != null) return adapter;\r
- \r
- Layer0 L0 = Layer0.getInstance(graph);\r
- Resource singleSuperType = graph.getPossibleObject(type, L0.Inherits);\r
- if(singleSuperType != null) {\r
- return getSingleTypeAdapter(graph, decl, key, instance, singleSuperType, possible);\r
- } else {\r
- return graph.syncRequest(new SingleTypeAdapter<T,C>(decl, key, instance, possible), TransientCacheAsyncListener.<Adapter<T,C>>instance());\r
- }\r
-\r
- } \r
- \r
-// private <T,C> void adaptSingleType(AsyncReadGraph graph, final AdapterDeclaration<T> decl, final C context, final Resource instance, final Resource type, final boolean possible, final AsyncProcedure<T> procedure) {\r
-//\r
-// @SuppressWarnings("unchecked")\r
-// Adapter<T,C> adapter = (Adapter<T,C>)decl.typeAdapters.get(type);\r
-// if(adapter != null) {\r
-//\r
-// adapter.adapt(graph, instance, context, procedure);\r
-//\r
-// } else {\r
-//\r
-// graph.forPossibleObject(type, graph.getService(Layer0.class).Inherits, new AsyncProcedure<Resource>() {\r
-//\r
-// @Override\r
-// public void exception(AsyncReadGraph graph, Throwable throwable) {\r
-//\r
-// procedure.exception(graph, new AdaptionException("Problems in reading super types for resource. ", throwable));\r
-//\r
-// }\r
-//\r
-// @Override\r
-// public void execute(AsyncReadGraph graph, Resource singleSuperType) {\r
-//\r
-// if(singleSuperType != null) {\r
-//\r
-// adaptSingleType(graph, decl, context, instance, singleSuperType, possible, procedure);\r
-//\r
-// } else {\r
-//\r
-// graph.asyncRequest(new Read<T>() {\r
-//\r
-// @Override\r
-// public T perform(ReadGraph graph)\r
-// throws DatabaseException {\r
-// return decl.adapt(graph, instance, context, possible);\r
-// }\r
-//\r
-// }, procedure);\r
-//\r
-// }\r
-//\r
-// }\r
-//\r
-// });\r
-//\r
-//\r
-// }\r
-//\r
-// }\r
-\r
- \r
- private static class SingleSuperTypeAdapter<T, C> extends TernaryRead<Pair<Class<T>, Class<?>>, Resource, Boolean, Adapter<T,C>> {\r
-\r
- final private AdapterDeclaration<T> decl;\r
- \r
- SingleSuperTypeAdapter(AdapterDeclaration<T> decl, Pair<Class<T>, Class<?>> key, Resource type, Boolean possible) {\r
- super(key, type, possible);\r
- this.decl = decl;\r
- }\r
- \r
- @Override\r
- public Adapter<T,C> perform(ReadGraph graph) throws DatabaseException {\r
- return decl.findAdapter(graph, parameter2, parameter3);\r
- }\r
-\r
- }\r
- \r
- private <T,C> void getSingleSuperTypeAdapter(AsyncReadGraph graph, final AdapterDeclaration<T> decl, final Pair<Class<T>, Class<?>> key, final Resource type, final Resource superType, final boolean possible, final AsyncProcedure<Adapter<T,C>> procedure) {\r
-\r
- @SuppressWarnings("unchecked")\r
- Adapter<T, C> adapter = (Adapter<T, C>)decl.instanceAdapters.get(superType);\r
- if(adapter != null) {\r
- procedure.execute(graph, adapter);\r
- } else {\r
-\r
- graph.forPossibleObject(superType, graph.getService(Layer0.class).Inherits, new AsyncProcedure<Resource>() {\r
-\r
- @Override\r
- public void exception(AsyncReadGraph graph, Throwable throwable) {\r
- procedure.exception(graph, new AdaptionException("Problems in reading super types for resource. ", throwable));\r
- }\r
-\r
- @Override\r
- public void execute(AsyncReadGraph graph, Resource singleSuperType) {\r
-\r
- if(singleSuperType != null) {\r
-\r
- getSingleSuperTypeAdapter(graph, decl, key, type, singleSuperType, possible, procedure);\r
-\r
- } else {\r
-\r
- graph.asyncRequest(new SingleSuperTypeAdapter<T,C>(decl, key, type, possible), procedure);\r
-\r
- }\r
-\r
- }\r
-\r
- });\r
-\r
- }\r
-\r
- }\r
-\r
- private <T,C> Adapter<T,C> getSingleSuperTypeAdapter(ReadGraph graph, final AdapterDeclaration<T> decl, final Pair<Class<T>, Class<?>> key, final Resource type, final Resource superType, final boolean possible) throws DatabaseException {\r
-\r
- @SuppressWarnings("unchecked")\r
- Adapter<T, C> adapter = (Adapter<T, C>)decl.instanceAdapters.get(superType);\r
- if(adapter != null) return adapter;\r
- \r
- Layer0 L0 = Layer0.getInstance(graph);\r
- Resource singleSuperType = graph.getPossibleObject(superType, L0.Inherits);\r
- if(singleSuperType != null) {\r
- return getSingleSuperTypeAdapter(graph, decl, key, type, singleSuperType, possible);\r
- } else {\r
- return graph.syncRequest(new SingleSuperTypeAdapter<T,C>(decl, key, type, possible));\r
- }\r
-\r
- }\r
- \r
-// private <T,C> void adaptSingleSupertype(AsyncReadGraph graph, final AdapterDeclaration<T> decl, final C context, final Resource type, final Resource superType, final boolean possible, final AsyncProcedure<T> procedure) {\r
-//\r
-// @SuppressWarnings("unchecked")\r
-// Adapter<T, C> adapter = (Adapter<T, C>)decl.instanceAdapters.get(superType);\r
-// if(adapter != null) {\r
-//\r
-// adapter.adapt(graph, type, context, procedure);\r
-//\r
-// } else {\r
-//\r
-// graph.forPossibleObject(superType, graph.getService(Layer0.class).Inherits, new AsyncProcedure<Resource>() {\r
-//\r
-// @Override\r
-// public void exception(AsyncReadGraph graph, Throwable throwable) {\r
-//\r
-// procedure.exception(graph, new AdaptionException("Problems in reading super types for resource. ", throwable));\r
-//\r
-// }\r
-//\r
-// @Override\r
-// public void execute(AsyncReadGraph graph, Resource singleSuperType) {\r
-//\r
-// if(singleSuperType != null) {\r
-//\r
-// adaptSingleSupertype(graph, decl, context, type, singleSuperType, possible, procedure);\r
-//\r
-// } else {\r
-//\r
-// graph.asyncRequest(new Read<T>() {\r
-//\r
-// @Override\r
-// public T perform(ReadGraph graph)\r
-// throws DatabaseException {\r
-// return decl.adapt(graph, type, context, possible);\r
-// }\r
-//\r
-// }, procedure);\r
-//\r
-// }\r
-//\r
-// }\r
-//\r
-// });\r
-//\r
-// }\r
-//\r
-// }\r
-\r
- @Override\r
- public <T> void adaptNew(AsyncReadGraph g, final Resource r, final Class<T> clazz, final boolean possible, final AsyncProcedure<T> procedure) {\r
-\r
- g.asyncRequest(new ReadRequest() {\r
-\r
- @Override\r
- public void run(ReadGraph graph) throws DatabaseException {\r
-\r
- final Pair<Class<T>, Class<?>> key = new Pair<Class<T>, Class<?>>(clazz, Resource.class); \r
-\r
- @SuppressWarnings("unchecked")\r
- AdapterDeclaration<T> decl =\r
- (AdapterDeclaration<T>)adapters.get(key);\r
-\r
- if(decl == null) {\r
- if(possible) {\r
- procedure.execute(graph, null);\r
- } else {\r
- procedure.exception(graph, new AdaptionException("There are no adapters declared or defined for class " + clazz + "."));\r
- }\r
- } else {\r
- try {\r
- procedure.execute(graph, decl.adaptNew(graph, r, possible));\r
- } catch (AdaptionException e) {\r
- if(possible) {\r
- procedure.execute(graph, null);\r
- } else {\r
- procedure.exception(graph, e);\r
- }\r
- } catch (ValidationException e) {\r
- procedure.exception(graph, e);\r
- } catch (DatabaseException e2) {\r
- procedure.exception(graph, new ServiceException(e2));\r
- }\r
- }\r
-\r
- }\r
-\r
- });\r
-\r
- }\r
-\r
- @Override\r
- public <T> void addInstanceAdapter(Resource resource, Class<T> targetClass, Adapter<T,?> adapter) {\r
- addInstanceAdapter(resource, targetClass, Resource.class, adapter);\r
- }\r
-\r
- @Override\r
- public <T> void addInstanceAdapter(Resource resource, Class<T> targetClass, Class<?> contextClass, Adapter<T,?> adapter) {\r
- synchronized (this) {\r
- getDeclaration(targetClass, contextClass).instanceAdapters.put(resource, adapter);\r
- }\r
- }\r
-\r
- @Override\r
- public <T> Adapter<T,?> removeInstanceAdapter(Resource resource, Class<T> targetClass) {\r
- return removeInstanceAdapter(resource, targetClass, Resource.class);\r
- }\r
- \r
- @Override\r
- public <T> Adapter<T,?> removeInstanceAdapter(Resource resource, Class<T> targetClass, Class<?> contextClass) {\r
- synchronized (this) {\r
- return getDeclaration(targetClass, contextClass).instanceAdapters.remove(resource);\r
- }\r
- }\r
-\r
- @Override\r
- public <T> void removeInstanceAdapter(Resource resource, Class<T> targetClass, Adapter<T,?> adapter) {\r
- removeInstanceAdapter(resource, targetClass, Resource.class, adapter);\r
- }\r
-\r
- @Override\r
- public <T> void removeInstanceAdapter(Resource resource, Class<T> targetClass, Class<?> contextClass, Adapter<T,?> adapter) {\r
- synchronized (this) {\r
- AdapterDeclaration<T> decl = getDeclaration(targetClass, contextClass);\r
- Adapter<T,?> existing = decl.instanceAdapters.get(resource);\r
- if (existing == adapter) {\r
- decl.instanceAdapters.remove(resource);\r
- }\r
- }\r
- }\r
-\r
- @Override\r
- public <T> void addAdapter(Resource type, Class<T> targetClass, Adapter<T,?> adapter) {\r
- addAdapter(type, targetClass, Resource.class, adapter);\r
- }\r
-\r
- @Override\r
- public <T> void addAdapter(Resource type, Class<T> targetClass, Class<?> contextClass, Adapter<T,?> adapter) {\r
- getDeclaration(targetClass, contextClass).typeAdapters.put(type, adapter);\r
- }\r
-\r
- @Override\r
- public <T> void declareAdapter(Resource type, Class<T> targetClass) {\r
- declareAdapter(type, targetClass, Resource.class);\r
- }\r
-\r
- @Override\r
- public <T> void declareAdapter(Resource type, Class<T> targetClass, Class<?> contextClass) {\r
- getDeclaration(targetClass, contextClass).baseTypes.add(type);\r
- }\r
-\r
- public static String safeName(ReadGraph g, Resource r) throws DatabaseException {\r
-// Builtins b = g.getBuiltins();\r
-// for(Resource name : g.getObjects(r, b.HasName))\r
-// return g.getValue(name);\r
-// for(Resource t : g.getObjects(r, b.InstanceOf))\r
-// for(Resource name : g.getObjects(t, b.HasName))\r
-// return ": "+ g.getValue(name);\r
-// for(Resource t : g.getObjects(r, b.Inherits))\r
-// for(Resource name : g.getObjects(t, b.HasName))\r
-// return "<T "+ g.getValue(name);\r
-// for(Resource t : g.getObjects(r, b.SubrelationOf))\r
-// for(Resource name : g.getObjects(t, b.HasName))\r
-// return "<R "+ g.getValue(name);\r
-// if(g.hasValue(r))\r
-// return "\"" + g.getValue(r) + "\"";\r
-// return "" + r.getResourceId();\r
- return NameUtils.getSafeName(g, r, true);\r
- }\r
-\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.db.services.adaption;
+
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.procedure.TObjectObjectProcedure;
+import gnu.trove.set.hash.THashSet;
+
+import org.simantics.db.AsyncReadGraph;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.adaption.Adapter;
+import org.simantics.db.adaption.AdaptionService;
+import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
+import org.simantics.db.common.procedure.single.SyncReadProcedure;
+import org.simantics.db.common.request.BinaryRead;
+import org.simantics.db.common.request.ReadRequest;
+import org.simantics.db.common.request.TernaryRead;
+import org.simantics.db.common.uri.ResourceToURI;
+import org.simantics.db.common.utils.NameUtils;
+import org.simantics.db.exception.AdaptionException;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.ServiceException;
+import org.simantics.db.exception.ValidationException;
+import org.simantics.db.procedure.AsyncProcedure;
+import org.simantics.db.request.AsyncRead;
+import org.simantics.db.request.Read;
+import org.simantics.layer0.Layer0;
+import org.simantics.utils.datastructures.Pair;
+
+public class AdaptionService2 implements AdaptionService {
+
+ THashMap<Pair<Class<?>,Class<?>>, AdapterDeclaration<?>> adapters =
+ new THashMap<Pair<Class<?>,Class<?>>, AdapterDeclaration<?>>();
+
+ /**
+ * Contains all adapter declarations and definitions for one class (clazz).
+ */
+ static class AdapterDeclaration<T> {
+ Class<T> clazz;
+ THashMap<Resource, Adapter<T,?>> typeAdapters =
+ new THashMap<Resource, Adapter<T,?>>();
+ THashMap<Resource, Adapter<T,?>> instanceAdapters =
+ new THashMap<Resource, Adapter<T,?>>();
+ THashSet<Resource> baseTypes = new THashSet<Resource>();
+
+ String getDescription(final ReadGraph g) {
+ final StringBuilder b = new StringBuilder();
+ b.append("The following adapters have been defined for ");
+ b.append(clazz.getCanonicalName());
+ b.append("\n");
+ typeAdapters.forEachEntry(new TObjectObjectProcedure<Resource, Adapter<T,?>>() {
+
+ @Override
+ public boolean execute(Resource arg0, Adapter<T,?> arg1) {
+ b.append(" type ");
+ try {
+ b.append(g.syncRequest(new ResourceToURI(arg0)));
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+ b.append(" : ");
+ b.append(arg1);
+ b.append('\n');
+ return true;
+ }
+
+ });
+
+ synchronized (this) {
+ instanceAdapters.forEachEntry(new TObjectObjectProcedure<Resource, Adapter<T,?>>() {
+
+ @Override
+ public boolean execute(Resource arg0, Adapter<T,?> arg1) {
+ b.append(" resource ");
+ try {
+ b.append(g.syncRequest(new ResourceToURI(arg0)));
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+ b.append(" : ");
+ b.append(arg1);
+ b.append('\n');
+ return true;
+ }
+
+ });
+ }
+ return b.toString();
+ }
+
+ public AdapterDeclaration(Class<T> clazz) {
+ this.clazz = clazz;
+ }
+
+ static class AdapterResult<T,C> {
+ Adapter<T,C> adapter;
+ Resource type;
+
+ public AdapterResult(Adapter<T,C> adapter, Resource type) {
+ this.adapter = adapter;
+ this.type = type;
+ }
+ }
+
+ /**
+ * The query returns the adapter inherited by the parameter type.
+ * The query is used only in the case, the type itself does not have
+ * an adapter. The second component of the result contains the type
+ * that originally contributed the adapter.
+ */
+ static class GetInheritedAdapter<T,C> extends BinaryRead<Resource, AdapterDeclaration<T>, AdapterResult<T,C>> {
+
+ public GetInheritedAdapter(Resource type, AdapterDeclaration<T> decl) {
+ super(type, decl);
+ }
+
+ AdapterDeclaration<T> getDeclaration() {
+ return parameter2;
+ }
+
+ @Override
+ public String toString() {
+ return "GetInheritedAdapter|" + parameter + "|" + parameter2;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public AdapterResult<T,C> perform(ReadGraph g) throws DatabaseException {
+ Layer0 b = Layer0.getInstance(g);
+ AdapterResult<T,C> result = null;
+ for(Resource supertype : g.getObjects(parameter, b.Inherits)) {
+ Adapter<T,C> adapter = (Adapter<T,C>)parameter2.typeAdapters.get(supertype);
+ if(adapter != null) {
+ if(result == null)
+ result = new AdapterResult<T,C>(adapter, supertype);
+ else if(!result.type.equals(supertype) &&
+ !g.isInheritedFrom(result.type, supertype)) {
+ if(g.isInheritedFrom(supertype, result.type))
+ result = new AdapterResult<T,C>(adapter, supertype);
+ else throw new AdaptionException("Type " +
+ safeName(g, parameter) + " inherits conflicting adapters from "
+ + safeName(g, supertype) + " and " + safeName(g, result.type));
+ }
+ }
+ else {
+ AdapterResult<T,C> temp =
+ g.syncRequest(new GetInheritedAdapter<T, C>(supertype, parameter2), TransientCacheAsyncListener.<AdapterResult<T,C>>instance());
+ if(temp != null) {
+ if(result == null)
+ result = temp;
+ else if(!result.type.equals(temp.type) &&
+ !g.isInheritedFrom(result.type, temp.type)) {
+ if(g.isInheritedFrom(temp.type, result.type))
+ result = temp;
+ else throw new AdaptionException("Type " +
+ safeName(g, parameter) + " inherits conflicting adapters from "
+ + safeName(g, temp.type) + " and " + safeName(g, result.type));
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ }
+
+ <C> void inheritedAdapter(AsyncReadGraph graph, Resource type, AsyncProcedure<AdapterResult<T,C>> procedure) {
+ graph.asyncRequest(new GetInheritedAdapter<T, C>(type, this), procedure);
+ }
+
+ Adapter<T,?> directAdapter(Resource r) {
+ Adapter<T,?> ret;
+ synchronized (this) {
+ ret = instanceAdapters.get(r);
+ }
+ return ret;
+ }
+
+ static class FindAdapter<T,C> extends BinaryRead<Resource, AdapterDeclaration<T>, Adapter<T,C>> {
+
+ public FindAdapter(Resource resource, AdapterDeclaration<T> decl) {
+ super(resource, decl);
+ }
+
+ @SuppressWarnings("unchecked")
+ Adapter<T,C> findAdapter(Resource r, ReadGraph g) throws DatabaseException {
+
+ {
+ Adapter<T,C> adapter;
+ synchronized (this) {
+ adapter = (Adapter<T,C>)parameter2.instanceAdapters.get(r);
+ }
+ if(adapter != null)
+ return adapter;
+ }
+
+ Layer0 b = Layer0.getInstance(g);
+
+ /*
+ * Try to find adapter from immediate types
+ */
+ AdapterResult<T,C> adapterResult = null;
+ for(Resource t : g.getObjects(r, b.InstanceOf)) {
+ Adapter<T,C> adapter = (Adapter<T,C>)parameter2.typeAdapters.get(t);
+ if(adapter != null) {
+ if(adapterResult == null)
+ adapterResult = new AdapterResult<T,C>(adapter, t);
+ else if(!adapterResult.type.equals(t) &&
+ !g.isInheritedFrom(adapterResult.type, t)) {
+ if(g.isInheritedFrom(t, adapterResult.type))
+ adapterResult = new AdapterResult<T,C>(adapter, t);
+ else throw new AdaptionException("Resource " +
+ safeName(g, r) + " has conflicting " + parameter2.clazz + "-adapters from "
+ + safeName(g, t) + " and " + safeName(g, adapterResult.type)
+ );
+ }
+ }
+ else {
+ AdapterResult<T,C> temp =
+ g.syncRequest(new GetInheritedAdapter<T, C>(t, parameter2), TransientCacheAsyncListener.<AdapterResult<T,C>>instance());
+ if(temp != null) {
+ if(adapterResult == null)
+ adapterResult = temp;
+ else if(!adapterResult.type.equals(temp.type) &&
+ !g.isInheritedFrom(adapterResult.type, temp.type)) {
+ if(g.isInheritedFrom(temp.type, adapterResult.type))
+ adapterResult = temp;
+ else throw new AdaptionException("Resource " +
+ safeName(g, r) + " has conflicting " + parameter2.clazz + "-adapters from "
+ + safeName(g, temp.type) + " and " + safeName(g, adapterResult.type)
+ );
+ }
+ }
+ }
+ }
+
+ if(adapterResult != null)
+ return adapterResult.adapter;
+
+ for(Resource t : g.getObjects(r, b.Inherits)) {
+ Adapter<T,C> adapter = findAdapter(t, g);
+ if(adapter != null)
+ return adapter;
+ }
+
+ for(Resource t : g.getObjects(r, b.SubrelationOf)) {
+ Adapter<T,C> adapter = findAdapter(t, g);
+ if(adapter != null)
+ return adapter;
+ }
+
+ return null;
+
+ }
+
+
+ @Override
+ public Adapter<T,C> perform(ReadGraph g) throws DatabaseException {
+ return (Adapter<T, C>)findAdapter(parameter, g);
+ }
+
+ }
+
+ /**
+ * The query returns either an adapter or adapted for the given
+ * resource. It is assumed that the resource itself does not
+ * have adapted.
+ */
+ class Adapt<C> implements Read<T> {
+
+ Resource resource;
+ C context;
+
+ public Adapt(Resource resource, C context) {
+ this.resource = resource;
+ this.context = context;
+ }
+
+ AdapterDeclaration<T> getDeclaration() {
+ return AdapterDeclaration.this;
+ }
+
+ @SuppressWarnings("unchecked")
+ Adapter<T,C> findAdapter(Resource r, ReadGraph g) throws DatabaseException {
+
+ {
+ Adapter<T,C> adapter;
+ synchronized (this) {
+ adapter = (Adapter<T,C>)instanceAdapters.get(r);
+ }
+ if(adapter != null)
+ return adapter;
+ }
+
+ Layer0 b = Layer0.getInstance(g);
+
+ /*
+ * Try to find adapter from immediate types
+ */
+ AdapterResult<T,C> adapterResult = null;
+ for(Resource t : g.getObjects(r, b.InstanceOf)) {
+ Adapter<T,C> adapter = (Adapter<T,C>)typeAdapters.get(t);
+ if(adapter != null) {
+ if(adapterResult == null)
+ adapterResult = new AdapterResult<T,C>(adapter, t);
+ else if(!adapterResult.type.equals(t) &&
+ !g.isInheritedFrom(adapterResult.type, t)) {
+ if(g.isInheritedFrom(t, adapterResult.type))
+ adapterResult = new AdapterResult<T,C>(adapter, t);
+ else throw new AdaptionException("Resource " +
+ safeName(g, r) + " has conflicting " + clazz + "-adapters from "
+ + safeName(g, t) + " and " + safeName(g, adapterResult.type)
+ );
+ }
+ }
+ else {
+ AdapterResult<T,C> temp =
+ g.syncRequest(new GetInheritedAdapter<T, C>(t, AdapterDeclaration.this));
+ if(temp != null) {
+ if(adapterResult == null)
+ adapterResult = temp;
+ else if(!adapterResult.type.equals(temp.type) &&
+ !g.isInheritedFrom(adapterResult.type, temp.type)) {
+ if(g.isInheritedFrom(temp.type, adapterResult.type))
+ adapterResult = temp;
+ else throw new AdaptionException("Resource " +
+ safeName(g, r) + " has conflicting " + clazz + "-adapters from "
+ + safeName(g, temp.type) + " and " + safeName(g, adapterResult.type)
+ );
+ }
+ }
+ }
+ }
+
+ if(adapterResult != null)
+ return adapterResult.adapter;
+
+ for(Resource t : g.getObjects(r, b.Inherits)) {
+ Adapter<T,C> adapter = findAdapter(t, g);
+ if(adapter != null)
+ return adapter;
+ }
+
+ for(Resource t : g.getObjects(r, b.SubrelationOf)) {
+ Adapter<T,C> adapter = findAdapter(t, g);
+ if(adapter != null)
+ return adapter;
+ }
+
+ return null;
+
+ }
+
+ @Override
+ public T perform(ReadGraph g) throws DatabaseException {
+
+ final Adapter<T,C> adapter = (Adapter<T, C>)findAdapter(resource, g);
+ if(adapter == null) return null;
+ else return g.syncRequest(new AsyncRead<T>() {
+
+ @Override
+ public void perform(AsyncReadGraph graph, AsyncProcedure<T> procedure) {
+// System.out.println("adapter=" + adapter);
+ adapter.adapt(graph, resource, context, procedure);
+ }
+
+ @Override
+ public int threadHash() {
+ return hashCode();
+ }
+
+ @Override
+ public int getFlags() {
+ return 0;
+ }
+
+ });
+
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public boolean equals(Object other) {
+
+ if (this == other)
+ return true;
+ else if (other == null)
+ return false;
+ else if (other.getClass() != Adapt.class)
+ return false;
+
+ return ((Adapt)other).resource.equals(resource)
+ && ((Adapt)other).context.equals(context)
+ && ((Adapt)other).getDeclaration()==getDeclaration();
+
+ }
+
+ @Override
+ public int hashCode() {
+ return resource.hashCode() + 31*((getClass().hashCode() + 41*(context.hashCode()) +
+ 71*getDeclaration().hashCode()));
+ }
+
+ }
+
+// void adapt2(AsyncReadGraph graph, Resource r, AsyncProcedure<T> procedure) {
+// graph.asyncRequest(new Adapt(r), procedure);
+// }
+
+ <C> Adapter<T,C> findAdapter(ReadGraph g, Resource r, boolean possible) throws DatabaseException {
+
+ Adapter<T,C> result = g.syncRequest(new FindAdapter<T,C>(r, AdapterDeclaration.this));
+ if(result != null) return result;
+
+ if (possible)
+ return null;
+
+ /*
+ * We couldn't adapt the resource. We analyze the situation little for
+ * better error message.
+ */
+ for(Resource dt : baseTypes) {
+ if(g.isInstanceOf(r, dt)) {
+ throw new AdaptionException("Couldn't find a " + clazz + "-adapter for resource " +
+ safeName(g, r) + " although it is instance of " +
+ safeName(g, dt) + "\n" +
+ getDescription(g));
+ }
+ }
+ throw new AdaptionException("Couldn't find a " + clazz + "-adapter for resource " +
+ safeName(g, r) +
+ ". This is because the resource is not instance of any type which the adapter is declared to.\n" +
+ getDescription(g));
+
+ }
+
+ <C> T adapt(ReadGraph g, Resource r, C context, boolean possible) throws DatabaseException {
+
+ T result = g.syncRequest(new Adapt<C>(r,context));
+ if(result != null) return result;
+
+ if (possible)
+ return null;
+
+ /*
+ * We couldn't adapt the resource. We analyze the situation little for
+ * better error message.
+ */
+ for(Resource dt : baseTypes) {
+ if(g.isInstanceOf(r, dt)) {
+ throw new AdaptionException("Couldn't find a " + clazz + "-adapter for resource " +
+ safeName(g, r) + " although it is instance of " +
+ safeName(g, dt) + "\n" +
+ getDescription(g));
+ }
+ }
+ throw new AdaptionException("Couldn't find a " + clazz + "-adapter for resource " +
+ safeName(g, r) +
+ ". This is because the resource is not instance of any type which the adapter is declared to.\n" +
+ getDescription(g));
+
+ }
+
+ T adaptNew(ReadGraph g, final Resource r, boolean possible) throws DatabaseException {
+
+ T result = new Adapt<Resource>(r,r).perform(g);
+ if (result != null)
+ return result;
+
+ if (possible)
+ return null;
+
+ for(Resource dt : baseTypes) {
+ if(g.isInstanceOf(r, dt)) {
+ throw new AdaptionException("Couldn't find a " + clazz + "-adapter for resource " +
+ safeName(g, r) + " although it is instance of " +
+ safeName(g, dt) + "\n" +
+ getDescription(g));
+ }
+ }
+ throw new AdaptionException("Couldn't find a " + clazz + "-adapter for resource " +
+ safeName(g, r) +
+ ". This is because the resource is not instance of any type which the adapter is declared to.\n" +
+ getDescription(g));
+
+ }
+
+ }
+
+ private <T> AdapterDeclaration<T> getDeclaration(Class<T> targetClass, Class<?> contextClass) {
+ Pair<Class<?>,Class<?>> key = new Pair<Class<?>,Class<?>>(targetClass, contextClass);
+ @SuppressWarnings("unchecked")
+ AdapterDeclaration<T> decl =
+ (AdapterDeclaration<T>)adapters.get(key);
+ if(decl == null) {
+ decl = new AdapterDeclaration<T>(targetClass);
+ adapters.put(key, decl);
+ }
+ return decl;
+ }
+
+ public <T,C> void getAdapter(AsyncReadGraph graph, final Resource r, final Class<C> contextClass, final Class<T> targetClass, final boolean possible, final AsyncProcedure<Adapter<T,C>> procedure) {
+
+ final Pair<Class<T>, Class<?>> key = new Pair<Class<T>, Class<?>>(targetClass, contextClass);
+ @SuppressWarnings("unchecked")
+ final AdapterDeclaration<T> decl = (AdapterDeclaration<T>)adapters.get(key);
+ if(decl == null) {
+
+ if(possible) {
+ procedure.execute(graph, null);
+ } else {
+ procedure.exception(graph, new AdaptionException("There are no adapters declared or defined for class " + targetClass + "."));
+ }
+
+ } else {
+
+ @SuppressWarnings("unchecked")
+ final Adapter<T,C> adapter = (Adapter<T,C>)decl.directAdapter(r);
+ if(adapter != null) {
+ procedure.execute(graph, adapter);
+ } else {
+ graph.forPossibleObject(r, graph.getService(Layer0.class).InstanceOf, new AsyncProcedure<Resource>() {
+
+ @Override
+ public void exception(AsyncReadGraph graph, Throwable throwable) {
+ procedure.exception(graph, new AdaptionException("Problems in reading types for resource. ", throwable));
+ }
+
+ @Override
+ public void execute(AsyncReadGraph graph, final Resource singleType) {
+ if(singleType != null) {
+ getSingleTypeAdapter(graph, decl, key, r, singleType, possible, procedure);
+ } else {
+ getSingleSuperTypeAdapter(graph, decl, key, r, r, possible, procedure);
+ }
+ }
+
+ });
+ }
+
+ }
+
+ }
+
+ @Override
+ public <T,C> void adapt(AsyncReadGraph graph, final Resource r, final C context, Class<C> contextClass, Class<T> targetClass, final boolean possible, final AsyncProcedure<T> procedure) {
+
+ getAdapter(graph, r, contextClass, targetClass, possible, new AsyncProcedure<Adapter<T,C>>() {
+
+ @Override
+ public void execute(AsyncReadGraph graph, Adapter<T, C> result) {
+ if(result == null) {
+ if(possible) {
+ procedure.execute(graph, null);
+ } else {
+ procedure.exception(graph, new AdaptionException("Internal error. getAdapter returned null and possible was false."));
+ }
+ } else {
+ result.adapt(graph, r, context, procedure);
+ }
+ }
+
+ @Override
+ public void exception(AsyncReadGraph graph, Throwable throwable) {
+ procedure.exception(graph, throwable);
+ }
+
+ });
+
+ }
+
+ @Override
+ public <T, C> T adapt(ReadGraph g, Resource r, C context, Class<C> contextClass, Class<T> targetClass, boolean possible) throws DatabaseException {
+
+ Adapter<T,C> adapter = getAdapter(g, r, context, contextClass, targetClass, possible);
+
+ SyncReadProcedure<T> procedure = new SyncReadProcedure<T>();
+ adapter.adapt(g, r, context, procedure);
+ procedure.checkAndThrow();
+ return procedure.result;
+
+ }
+
+ private <T, C> Adapter<T,C> getAdapter(ReadGraph g, Resource r, C context, Class<C> contextClass, Class<T> targetClass, boolean possible) throws DatabaseException {
+
+ final Pair<Class<T>, Class<?>> key = new Pair<Class<T>, Class<?>>(targetClass, contextClass);
+ @SuppressWarnings("unchecked")
+ final AdapterDeclaration<T> decl = (AdapterDeclaration<T>)adapters.get(key);
+ if(decl == null) {
+
+ if(possible) return null;
+ else throw new AdaptionException("There are no adapters declared or defined for class " + targetClass + ".");
+
+ } else {
+
+ @SuppressWarnings("unchecked")
+ final Adapter<T,C> adapter = (Adapter<T,C>)decl.directAdapter(r);
+ if(adapter != null) return adapter;
+
+ Layer0 L0 = Layer0.getInstance(g);
+ Resource singleType = g.getPossibleObject(r, L0.InstanceOf);
+ if(singleType != null) {
+ return getSingleTypeAdapter(g, decl, key, r, singleType, possible);
+ } else {
+ return getSingleSuperTypeAdapter(g, decl, key, r, r, possible);
+ }
+
+ }
+
+ }
+
+ private static class SingleTypeAdapter<T, C> extends TernaryRead<Pair<Class<T>, Class<?>>, Resource, Boolean, Adapter<T,C>> {
+
+ final private AdapterDeclaration<T> decl;
+
+ SingleTypeAdapter(AdapterDeclaration<T> decl, Pair<Class<T>, Class<?>> key, Resource instance, Boolean possible) {
+ super(key, instance, possible);
+ this.decl = decl;
+ }
+
+ @Override
+ public Adapter<T,C> perform(ReadGraph graph) throws DatabaseException {
+ return decl.findAdapter(graph, parameter2, parameter3);
+ }
+
+ }
+
+ private <T,C> void getSingleTypeAdapter(AsyncReadGraph graph, final AdapterDeclaration<T> decl, final Pair<Class<T>, Class<?>> key, final Resource instance, final Resource type, final boolean possible, final AsyncProcedure<Adapter<T,C>> procedure) {
+
+ @SuppressWarnings("unchecked")
+ Adapter<T,C> adapter = (Adapter<T,C>)decl.typeAdapters.get(type);
+ if(adapter != null) {
+ procedure.execute(graph, adapter);
+ } else {
+ graph.forPossibleObject(type, graph.getService(Layer0.class).Inherits, new AsyncProcedure<Resource>() {
+
+ @Override
+ public void exception(AsyncReadGraph graph, Throwable throwable) {
+ procedure.exception(graph, new AdaptionException("Problems in reading super types for resource. ", throwable));
+ }
+
+ @Override
+ public void execute(AsyncReadGraph graph, Resource singleSuperType) {
+
+ if(singleSuperType != null) {
+ getSingleTypeAdapter(graph, decl, key, instance, singleSuperType, possible, procedure);
+ } else {
+ graph.asyncRequest(new SingleTypeAdapter<T,C>(decl, key, instance, possible), procedure);
+ }
+
+ }
+
+ });
+
+
+ }
+
+ }
+
+ private <T,C> Adapter<T,C> getSingleTypeAdapter(ReadGraph graph, final AdapterDeclaration<T> decl, final Pair<Class<T>, Class<?>> key, final Resource instance, final Resource type, final boolean possible) throws DatabaseException {
+
+ @SuppressWarnings("unchecked")
+ Adapter<T,C> adapter = (Adapter<T,C>)decl.typeAdapters.get(type);
+ if(adapter != null) return adapter;
+
+ Layer0 L0 = Layer0.getInstance(graph);
+ Resource singleSuperType = graph.getPossibleObject(type, L0.Inherits);
+ if(singleSuperType != null) {
+ return getSingleTypeAdapter(graph, decl, key, instance, singleSuperType, possible);
+ } else {
+ return graph.syncRequest(new SingleTypeAdapter<T,C>(decl, key, instance, possible), TransientCacheAsyncListener.<Adapter<T,C>>instance());
+ }
+
+ }
+
+// private <T,C> void adaptSingleType(AsyncReadGraph graph, final AdapterDeclaration<T> decl, final C context, final Resource instance, final Resource type, final boolean possible, final AsyncProcedure<T> procedure) {
+//
+// @SuppressWarnings("unchecked")
+// Adapter<T,C> adapter = (Adapter<T,C>)decl.typeAdapters.get(type);
+// if(adapter != null) {
+//
+// adapter.adapt(graph, instance, context, procedure);
+//
+// } else {
+//
+// graph.forPossibleObject(type, graph.getService(Layer0.class).Inherits, new AsyncProcedure<Resource>() {
+//
+// @Override
+// public void exception(AsyncReadGraph graph, Throwable throwable) {
+//
+// procedure.exception(graph, new AdaptionException("Problems in reading super types for resource. ", throwable));
+//
+// }
+//
+// @Override
+// public void execute(AsyncReadGraph graph, Resource singleSuperType) {
+//
+// if(singleSuperType != null) {
+//
+// adaptSingleType(graph, decl, context, instance, singleSuperType, possible, procedure);
+//
+// } else {
+//
+// graph.asyncRequest(new Read<T>() {
+//
+// @Override
+// public T perform(ReadGraph graph)
+// throws DatabaseException {
+// return decl.adapt(graph, instance, context, possible);
+// }
+//
+// }, procedure);
+//
+// }
+//
+// }
+//
+// });
+//
+//
+// }
+//
+// }
+
+
+ private static class SingleSuperTypeAdapter<T, C> extends TernaryRead<Pair<Class<T>, Class<?>>, Resource, Boolean, Adapter<T,C>> {
+
+ final private AdapterDeclaration<T> decl;
+
+ SingleSuperTypeAdapter(AdapterDeclaration<T> decl, Pair<Class<T>, Class<?>> key, Resource type, Boolean possible) {
+ super(key, type, possible);
+ this.decl = decl;
+ }
+
+ @Override
+ public Adapter<T,C> perform(ReadGraph graph) throws DatabaseException {
+ return decl.findAdapter(graph, parameter2, parameter3);
+ }
+
+ }
+
+ private <T,C> void getSingleSuperTypeAdapter(AsyncReadGraph graph, final AdapterDeclaration<T> decl, final Pair<Class<T>, Class<?>> key, final Resource type, final Resource superType, final boolean possible, final AsyncProcedure<Adapter<T,C>> procedure) {
+
+ @SuppressWarnings("unchecked")
+ Adapter<T, C> adapter = (Adapter<T, C>)decl.instanceAdapters.get(superType);
+ if(adapter != null) {
+ procedure.execute(graph, adapter);
+ } else {
+
+ graph.forPossibleObject(superType, graph.getService(Layer0.class).Inherits, new AsyncProcedure<Resource>() {
+
+ @Override
+ public void exception(AsyncReadGraph graph, Throwable throwable) {
+ procedure.exception(graph, new AdaptionException("Problems in reading super types for resource. ", throwable));
+ }
+
+ @Override
+ public void execute(AsyncReadGraph graph, Resource singleSuperType) {
+
+ if(singleSuperType != null) {
+
+ getSingleSuperTypeAdapter(graph, decl, key, type, singleSuperType, possible, procedure);
+
+ } else {
+
+ graph.asyncRequest(new SingleSuperTypeAdapter<T,C>(decl, key, type, possible), procedure);
+
+ }
+
+ }
+
+ });
+
+ }
+
+ }
+
+ private <T,C> Adapter<T,C> getSingleSuperTypeAdapter(ReadGraph graph, final AdapterDeclaration<T> decl, final Pair<Class<T>, Class<?>> key, final Resource type, final Resource superType, final boolean possible) throws DatabaseException {
+
+ @SuppressWarnings("unchecked")
+ Adapter<T, C> adapter = (Adapter<T, C>)decl.instanceAdapters.get(superType);
+ if(adapter != null) return adapter;
+
+ Layer0 L0 = Layer0.getInstance(graph);
+ Resource singleSuperType = graph.getPossibleObject(superType, L0.Inherits);
+ if(singleSuperType != null) {
+ return getSingleSuperTypeAdapter(graph, decl, key, type, singleSuperType, possible);
+ } else {
+ return graph.syncRequest(new SingleSuperTypeAdapter<T,C>(decl, key, type, possible));
+ }
+
+ }
+
+// private <T,C> void adaptSingleSupertype(AsyncReadGraph graph, final AdapterDeclaration<T> decl, final C context, final Resource type, final Resource superType, final boolean possible, final AsyncProcedure<T> procedure) {
+//
+// @SuppressWarnings("unchecked")
+// Adapter<T, C> adapter = (Adapter<T, C>)decl.instanceAdapters.get(superType);
+// if(adapter != null) {
+//
+// adapter.adapt(graph, type, context, procedure);
+//
+// } else {
+//
+// graph.forPossibleObject(superType, graph.getService(Layer0.class).Inherits, new AsyncProcedure<Resource>() {
+//
+// @Override
+// public void exception(AsyncReadGraph graph, Throwable throwable) {
+//
+// procedure.exception(graph, new AdaptionException("Problems in reading super types for resource. ", throwable));
+//
+// }
+//
+// @Override
+// public void execute(AsyncReadGraph graph, Resource singleSuperType) {
+//
+// if(singleSuperType != null) {
+//
+// adaptSingleSupertype(graph, decl, context, type, singleSuperType, possible, procedure);
+//
+// } else {
+//
+// graph.asyncRequest(new Read<T>() {
+//
+// @Override
+// public T perform(ReadGraph graph)
+// throws DatabaseException {
+// return decl.adapt(graph, type, context, possible);
+// }
+//
+// }, procedure);
+//
+// }
+//
+// }
+//
+// });
+//
+// }
+//
+// }
+
+ @Override
+ public <T> void adaptNew(AsyncReadGraph g, final Resource r, final Class<T> clazz, final boolean possible, final AsyncProcedure<T> procedure) {
+
+ g.asyncRequest(new ReadRequest() {
+
+ @Override
+ public void run(ReadGraph graph) throws DatabaseException {
+
+ final Pair<Class<T>, Class<?>> key = new Pair<Class<T>, Class<?>>(clazz, Resource.class);
+
+ @SuppressWarnings("unchecked")
+ AdapterDeclaration<T> decl =
+ (AdapterDeclaration<T>)adapters.get(key);
+
+ if(decl == null) {
+ if(possible) {
+ procedure.execute(graph, null);
+ } else {
+ procedure.exception(graph, new AdaptionException("There are no adapters declared or defined for class " + clazz + "."));
+ }
+ } else {
+ try {
+ procedure.execute(graph, decl.adaptNew(graph, r, possible));
+ } catch (AdaptionException e) {
+ if(possible) {
+ procedure.execute(graph, null);
+ } else {
+ procedure.exception(graph, e);
+ }
+ } catch (ValidationException e) {
+ procedure.exception(graph, e);
+ } catch (DatabaseException e2) {
+ procedure.exception(graph, new ServiceException(e2));
+ }
+ }
+
+ }
+
+ });
+
+ }
+
+ @Override
+ public <T> void addInstanceAdapter(Resource resource, Class<T> targetClass, Adapter<T,?> adapter) {
+ addInstanceAdapter(resource, targetClass, Resource.class, adapter);
+ }
+
+ @Override
+ public <T> void addInstanceAdapter(Resource resource, Class<T> targetClass, Class<?> contextClass, Adapter<T,?> adapter) {
+ synchronized (this) {
+ getDeclaration(targetClass, contextClass).instanceAdapters.put(resource, adapter);
+ }
+ }
+
+ @Override
+ public <T> Adapter<T,?> removeInstanceAdapter(Resource resource, Class<T> targetClass) {
+ return removeInstanceAdapter(resource, targetClass, Resource.class);
+ }
+
+ @Override
+ public <T> Adapter<T,?> removeInstanceAdapter(Resource resource, Class<T> targetClass, Class<?> contextClass) {
+ synchronized (this) {
+ return getDeclaration(targetClass, contextClass).instanceAdapters.remove(resource);
+ }
+ }
+
+ @Override
+ public <T> void removeInstanceAdapter(Resource resource, Class<T> targetClass, Adapter<T,?> adapter) {
+ removeInstanceAdapter(resource, targetClass, Resource.class, adapter);
+ }
+
+ @Override
+ public <T> void removeInstanceAdapter(Resource resource, Class<T> targetClass, Class<?> contextClass, Adapter<T,?> adapter) {
+ synchronized (this) {
+ AdapterDeclaration<T> decl = getDeclaration(targetClass, contextClass);
+ Adapter<T,?> existing = decl.instanceAdapters.get(resource);
+ if (existing == adapter) {
+ decl.instanceAdapters.remove(resource);
+ }
+ }
+ }
+
+ @Override
+ public <T> void addAdapter(Resource type, Class<T> targetClass, Adapter<T,?> adapter) {
+ addAdapter(type, targetClass, Resource.class, adapter);
+ }
+
+ @Override
+ public <T> void addAdapter(Resource type, Class<T> targetClass, Class<?> contextClass, Adapter<T,?> adapter) {
+ getDeclaration(targetClass, contextClass).typeAdapters.put(type, adapter);
+ }
+
+ @Override
+ public <T> void declareAdapter(Resource type, Class<T> targetClass) {
+ declareAdapter(type, targetClass, Resource.class);
+ }
+
+ @Override
+ public <T> void declareAdapter(Resource type, Class<T> targetClass, Class<?> contextClass) {
+ getDeclaration(targetClass, contextClass).baseTypes.add(type);
+ }
+
+ public static String safeName(ReadGraph g, Resource r) throws DatabaseException {
+// Builtins b = g.getBuiltins();
+// for(Resource name : g.getObjects(r, b.HasName))
+// return g.getValue(name);
+// for(Resource t : g.getObjects(r, b.InstanceOf))
+// for(Resource name : g.getObjects(t, b.HasName))
+// return ": "+ g.getValue(name);
+// for(Resource t : g.getObjects(r, b.Inherits))
+// for(Resource name : g.getObjects(t, b.HasName))
+// return "<T "+ g.getValue(name);
+// for(Resource t : g.getObjects(r, b.SubrelationOf))
+// for(Resource name : g.getObjects(t, b.HasName))
+// return "<R "+ g.getValue(name);
+// if(g.hasValue(r))
+// return "\"" + g.getValue(r) + "\"";
+// return "" + r.getResourceId();
+ return NameUtils.getSafeName(g, r, true);
+ }
+
}
\ No newline at end of file