You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by ni...@apache.org on 2016/12/17 10:27:43 UTC
[07/81] [abbrv] [partial] zest-java git commit: ZEST-195 ;
Replace all "zest" with "polygene"
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ApplicationInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ApplicationInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ApplicationInstance.java
new file mode 100644
index 0000000..e27a0af
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ApplicationInstance.java
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ */
+package org.apache.polygene.runtime.structure;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+import org.apache.polygene.api.activation.ActivationEventListener;
+import org.apache.polygene.api.activation.ActivationException;
+import org.apache.polygene.api.activation.PassivationException;
+import org.apache.polygene.api.common.MetaInfo;
+import org.apache.polygene.api.structure.Application;
+import org.apache.polygene.api.structure.ApplicationDescriptor;
+import org.apache.polygene.api.structure.Layer;
+import org.apache.polygene.api.structure.Module;
+import org.apache.polygene.bootstrap.PolygeneRuntime;
+import org.apache.polygene.runtime.activation.ActivationDelegate;
+
+/**
+ * Instance of a Polygene application. Contains a list of layers which are managed by this application
+ */
+public class ApplicationInstance
+ implements Application
+{
+
+ // Constructor parameters
+ private final ApplicationModel applicationModel;
+ private final PolygeneRuntime runtime;
+ private final MetaInfo instanceMetaInfo;
+ // Eager instance objects
+ private final ActivationDelegate activation;
+ private final List<LayerInstance> layerInstances;
+
+ public ApplicationInstance( ApplicationModel model, PolygeneRuntime runtime, MetaInfo instanceMetaInfo )
+ {
+ // Constructor parameters
+ this.applicationModel = model;
+ this.runtime = runtime;
+ this.instanceMetaInfo = instanceMetaInfo;
+
+ // Eager instance objects
+ activation = new ActivationDelegate( this );
+ layerInstances = new ArrayList<>();
+ }
+
+ @Override
+ public String toString()
+ {
+ return name();
+ }
+
+ // Implementation of Application
+ @Override
+ public String name()
+ {
+ return applicationModel.name();
+ }
+
+ @Override
+ public String version()
+ {
+ return applicationModel.version();
+ }
+
+ @Override
+ public Mode mode()
+ {
+ return applicationModel.mode();
+ }
+
+ @Override
+ public Layer findLayer( String layerName )
+ {
+ for( LayerInstance layerInstance : layerInstances )
+ {
+ if( layerInstance.model().name().equals( layerName ) )
+ {
+ return layerInstance;
+ }
+ }
+
+ throw new IllegalArgumentException( "No such layer:" + layerName );
+ }
+
+ @Override
+ public Module findModule( String layerName, String moduleName )
+ {
+ for( LayerInstance layerInstance : layerInstances )
+ {
+ if( layerInstance.model().name().equals( layerName ) )
+ {
+ return layerInstance.findModule( moduleName );
+ }
+ }
+
+ throw new IllegalArgumentException( "No such layer:" + layerName );
+ }
+
+ @Override
+ public Stream<? extends Layer> layers()
+ {
+ return layerInstances.stream();
+ }
+
+ @Override
+ public ApplicationDescriptor descriptor()
+ {
+ return applicationModel;
+ }
+
+ // Implementation of MetaInfoHolder
+ @Override
+ public <T> T metaInfo( Class<T> infoType )
+ {
+ return instanceMetaInfo.get( infoType );
+ }
+
+ // Implementation of Activation
+ @Override
+ public void activate()
+ throws ActivationException
+ {
+ activation.activate( applicationModel.newActivatorsInstance(), layerInstances );
+ }
+
+ @Override
+ public void passivate()
+ throws PassivationException
+ {
+ activation.passivate();
+ }
+
+ @Override
+ public void registerActivationEventListener( ActivationEventListener listener )
+ {
+ activation.registerActivationEventListener( listener );
+ }
+
+ @Override
+ public void deregisterActivationEventListener( ActivationEventListener listener )
+ {
+ activation.deregisterActivationEventListener( listener );
+ }
+
+ // Other methods
+ void addLayer( LayerInstance layer )
+ {
+ layer.registerActivationEventListener( activation );
+ layerInstances.add( layer );
+ }
+
+ public PolygeneRuntime runtime()
+ {
+ return runtime;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ApplicationModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ApplicationModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ApplicationModel.java
new file mode 100644
index 0000000..a163bed
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ApplicationModel.java
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ */
+package org.apache.polygene.runtime.structure;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.polygene.api.PolygeneAPI;
+import org.apache.polygene.api.activation.ActivationException;
+import org.apache.polygene.api.common.InvalidApplicationException;
+import org.apache.polygene.api.common.MetaInfo;
+import org.apache.polygene.api.structure.Application;
+import org.apache.polygene.api.structure.ApplicationDescriptor;
+import org.apache.polygene.api.structure.LayerDescriptor;
+import org.apache.polygene.api.util.HierarchicalVisitor;
+import org.apache.polygene.bootstrap.PolygeneRuntime;
+import org.apache.polygene.runtime.activation.ActivatorsInstance;
+import org.apache.polygene.runtime.activation.ActivatorsModel;
+import org.apache.polygene.runtime.injection.InjectionProviderFactory;
+import org.apache.polygene.runtime.injection.provider.InjectionProviderFactoryStrategy;
+
+/**
+ * JAVADOC
+ */
+public final class ApplicationModel
+ implements ApplicationDescriptor
+{
+ private final String name;
+ private final String version;
+ private final Application.Mode mode;
+ private final MetaInfo metaInfo;
+ private final ActivatorsModel<Application> activatorsModel;
+ private final List<LayerModel> layers;
+ private final InjectionProviderFactory ipf;
+
+ public ApplicationModel( String name,
+ String version,
+ Application.Mode mode,
+ MetaInfo metaInfo,
+ ActivatorsModel<Application> activatorsModel,
+ List<LayerModel> layers
+ )
+ {
+ this.name = name;
+ this.version = version;
+ this.mode = mode;
+ this.metaInfo = metaInfo;
+ this.activatorsModel = activatorsModel;
+ this.layers = layers;
+ ipf = new InjectionProviderFactoryStrategy( metaInfo );
+ }
+
+ @Override
+ public String name()
+ {
+ return name;
+ }
+
+ public String version()
+ {
+ return version;
+ }
+
+ public Application.Mode mode()
+ {
+ return mode;
+ }
+
+ public MetaInfo metaInfo()
+ {
+ return metaInfo;
+ }
+
+ public ActivatorsInstance<Application> newActivatorsInstance()
+ throws ActivationException
+ {
+ return new ActivatorsInstance<>( activatorsModel.newInstances() );
+ }
+
+ // SPI
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor )
+ throws ThrowableType
+ {
+ if( visitor.visitEnter( this ) )
+ {
+ if( activatorsModel.accept( visitor ) )
+ {
+ for( LayerModel layer : layers )
+ {
+ if( !layer.accept( visitor ) )
+ {
+ break;
+ }
+ }
+ }
+ }
+ return visitor.visitLeave( this );
+ }
+
+ @Override
+ public ApplicationInstance newInstance( PolygeneAPI runtime, Object... importedServiceInstances )
+ throws InvalidApplicationException
+ {
+ MetaInfo instanceMetaInfo = new MetaInfo( metaInfo );
+ for( Object importedServiceInstance : importedServiceInstances )
+ {
+ instanceMetaInfo.set( importedServiceInstance );
+ }
+
+ ApplicationInstance applicationInstance = new ApplicationInstance( this, (PolygeneRuntime) runtime, instanceMetaInfo );
+
+ // Create layer instances
+ Map<LayerDescriptor, LayerDescriptor> layerInstanceMap = new HashMap<>();
+ Map<LayerDescriptor, List<LayerDescriptor>> usedLayers = new HashMap<>();
+ for( LayerModel layer : layers )
+ {
+ List<LayerDescriptor> usedLayerInstances = new ArrayList<>();
+ usedLayers.put( layer, usedLayerInstances );
+ UsedLayersInstance usedLayersInstance = layer.usedLayers().newInstance( usedLayerInstances );
+ LayerInstance layerInstance = layer.newInstance( applicationInstance );
+ applicationInstance.addLayer( layerInstance );
+ layerInstanceMap.put( layer, layerInstance.descriptor() );
+ }
+
+ // Resolve used layer instances
+ for( LayerModel layer : layers )
+ {
+ List<LayerDescriptor> usedLayerInstances = usedLayers.get( layer );
+ layer.usedLayers().layers().forEach(
+ usedLayer ->
+ {
+ LayerDescriptor layerDescriptor = layerInstanceMap.get( usedLayer );
+ if( layerDescriptor == null )
+ {
+ throw new InvalidApplicationException( "Could not find used layer:" + usedLayer
+ .name() );
+ }
+ usedLayerInstances.add( layerDescriptor );
+ } );
+ }
+
+ return applicationInstance;
+ }
+
+ public InjectionProviderFactory injectionProviderFactory()
+ {
+ return ipf;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "ApplicationModel" +
+ "{name='" + name + '\'' +
+ ", version='" + version + '\'' +
+ ", mode=" + mode +
+ '}';
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/structure/LayerInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/structure/LayerInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/LayerInstance.java
new file mode 100644
index 0000000..09201fb
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/LayerInstance.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ */
+package org.apache.polygene.runtime.structure;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+import org.apache.polygene.api.activation.ActivationEventListener;
+import org.apache.polygene.api.activation.ActivationException;
+import org.apache.polygene.api.activation.PassivationException;
+import org.apache.polygene.api.structure.Application;
+import org.apache.polygene.api.structure.Layer;
+import org.apache.polygene.api.structure.LayerDescriptor;
+import org.apache.polygene.api.structure.Module;
+import org.apache.polygene.runtime.activation.ActivationDelegate;
+
+/**
+ * Instance of a Polygene application layer. Contains a list of modules which are managed by this layer.
+ */
+public class LayerInstance
+ implements Layer
+{
+
+ // Constructor parameters
+ private final LayerModel layerModel;
+ private final ApplicationInstance applicationInstance;
+
+ // Eager instance objects
+ private final ActivationDelegate activation;
+ private final List<ModuleInstance> moduleInstances;
+
+ public LayerInstance( LayerModel model,
+ ApplicationInstance applicationInstance
+ )
+ {
+ // Constructor parameters
+ this.layerModel = model;
+ this.applicationInstance = applicationInstance;
+
+ // Eager instance objects
+ activation = new ActivationDelegate( this );
+ moduleInstances = new ArrayList<>();
+ }
+
+ @Override
+ public String toString()
+ {
+ return layerModel.toString();
+ }
+
+ // Implementation of Layer
+ @Override
+ public String name()
+ {
+ return layerModel.name();
+ }
+
+ @Override
+ public Application application()
+ {
+ return applicationInstance;
+ }
+
+ // Implementation of MetaInfoHolder
+ @Override
+ public <T> T metaInfo( Class<T> infoType )
+ {
+ return layerModel.metaInfo( infoType );
+ }
+
+ // Implementation of Activation
+ @Override
+ public void activate()
+ throws ActivationException
+ {
+ activation.activate( layerModel.newActivatorsInstance(), moduleInstances );
+ }
+
+ @Override
+ public void passivate()
+ throws PassivationException
+ {
+ activation.passivate();
+ }
+
+ @Override
+ public void registerActivationEventListener( ActivationEventListener listener )
+ {
+ activation.registerActivationEventListener( listener );
+ }
+
+ @Override
+ public void deregisterActivationEventListener( ActivationEventListener listener )
+ {
+ activation.deregisterActivationEventListener( listener );
+ }
+
+ @Override
+ public Stream<? extends Module> modules()
+ {
+ return moduleInstances.stream();
+ }
+
+ @Override
+ public LayerDescriptor descriptor()
+ {
+ return layerModel;
+ }
+
+ void addModule( ModuleInstance module )
+ {
+ module.registerActivationEventListener( activation );
+ moduleInstances.add( module );
+ }
+
+ public LayerModel model()
+ {
+ return layerModel;
+ }
+
+ /* package */ ModuleInstance findModule( String moduleName )
+ {
+ for( ModuleInstance moduleInstance : moduleInstances )
+ {
+ if( moduleInstance.model().name().equals( moduleName ) )
+ {
+ return moduleInstance;
+ }
+ }
+
+ throw new IllegalArgumentException( "No such module:" + moduleName );
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/structure/LayerModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/structure/LayerModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/LayerModel.java
new file mode 100644
index 0000000..04ca846
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/LayerModel.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ */
+package org.apache.polygene.runtime.structure;
+
+import java.util.List;
+import java.util.stream.Stream;
+import org.apache.polygene.api.activation.ActivationException;
+import org.apache.polygene.api.common.MetaInfo;
+import org.apache.polygene.api.common.Visibility;
+import org.apache.polygene.api.composite.ModelDescriptor;
+import org.apache.polygene.api.composite.TransientDescriptor;
+import org.apache.polygene.api.entity.EntityDescriptor;
+import org.apache.polygene.api.object.ObjectDescriptor;
+import org.apache.polygene.api.structure.Layer;
+import org.apache.polygene.api.structure.LayerDescriptor;
+import org.apache.polygene.api.util.HierarchicalVisitor;
+import org.apache.polygene.api.util.VisitableHierarchy;
+import org.apache.polygene.api.value.ValueDescriptor;
+import org.apache.polygene.runtime.activation.ActivatorsInstance;
+import org.apache.polygene.runtime.activation.ActivatorsModel;
+
+/**
+ * JAVADOC
+ */
+public final class LayerModel
+ implements LayerDescriptor, VisitableHierarchy<Object, Object>
+{
+ // Model
+ private final String name;
+ private final MetaInfo metaInfo;
+ private final UsedLayersModel usedLayersModel;
+ private final ActivatorsModel<Layer> activatorsModel;
+ private final List<ModuleModel> modules;
+ private LayerInstance layerInstance;
+
+ public LayerModel( String name,
+ MetaInfo metaInfo,
+ UsedLayersModel usedLayersModel,
+ ActivatorsModel<Layer> activatorsModel,
+ List<ModuleModel> modules
+ )
+ {
+ this.name = name;
+ this.metaInfo = metaInfo;
+ this.usedLayersModel = usedLayersModel;
+ this.activatorsModel = activatorsModel;
+ this.modules = modules;
+ }
+
+ @Override
+ public String name()
+ {
+ return name;
+ }
+
+ public <T> T metaInfo( Class<T> infoType )
+ {
+ return metaInfo.get( infoType );
+ }
+
+ public Iterable<ModuleModel> modules()
+ {
+ return modules;
+ }
+
+ @Override
+ public UsedLayersModel usedLayers()
+ {
+ return usedLayersModel;
+ }
+
+ public ActivatorsInstance<Layer> newActivatorsInstance()
+ throws ActivationException
+ {
+ return new ActivatorsInstance<>( activatorsModel.newInstances() );
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> modelVisitor )
+ throws ThrowableType
+ {
+ if( modelVisitor.visitEnter( this ) )
+ {
+ if( activatorsModel.accept( modelVisitor ) )
+ {
+ for( ModuleModel module : modules )
+ {
+ if( !module.accept( modelVisitor ) )
+ {
+ break;
+ }
+ }
+ }
+ }
+ return modelVisitor.visitLeave( this );
+ }
+
+ @Override
+ public Layer instance()
+ {
+ return layerInstance;
+ }
+
+ public LayerInstance newInstance( ApplicationInstance applicationInstance )
+ {
+ layerInstance = new LayerInstance( this, applicationInstance );
+ for( ModuleModel module : modules )
+ {
+ ModuleInstance moduleInstance = module.newInstance( this );
+ layerInstance.addModule( moduleInstance );
+ }
+ return layerInstance;
+ }
+
+ @Override
+ public Stream<? extends ObjectDescriptor> visibleObjects( final Visibility visibility )
+ {
+ return modules.stream().flatMap( module -> module.visibleObjects( visibility ) );
+ }
+
+ @Override
+ public Stream<? extends TransientDescriptor> visibleTransients( final Visibility visibility )
+ {
+ return modules.stream().flatMap( module -> module.visibleTransients( visibility ) );
+ }
+
+ @Override
+ public Stream<? extends EntityDescriptor> visibleEntities( final Visibility visibility )
+ {
+ return modules.stream().flatMap( module -> module.visibleEntities( visibility ) );
+ }
+
+ /* package */
+ @Override
+ public Stream<? extends ValueDescriptor> visibleValues( final Visibility visibility )
+ {
+ return modules.stream().flatMap( module -> module.visibleValues( visibility ) );
+ }
+
+ /* package */
+ @Override
+ public Stream<? extends ModelDescriptor> visibleServices( final Visibility visibility )
+ {
+ return modules.stream().flatMap( module -> module.visibleServices( visibility ) );
+ }
+
+
+ @Override
+ public String toString()
+ {
+ return name;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ModuleClassLoader.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ModuleClassLoader.java b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ModuleClassLoader.java
new file mode 100644
index 0000000..65873f1
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ModuleClassLoader.java
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ */
+
+package org.apache.polygene.runtime.structure;
+
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import org.apache.polygene.api.common.Visibility;
+import org.apache.polygene.api.composite.AmbiguousTypeException;
+import org.apache.polygene.api.composite.ModelDescriptor;
+
+import static java.util.stream.Stream.concat;
+import static org.apache.polygene.api.common.Visibility.application;
+import static org.apache.polygene.api.common.Visibility.module;
+import static org.apache.polygene.api.util.Classes.modelTypeSpecification;
+
+// Module ClassLoader
+class ModuleClassLoader
+ extends ClassLoader
+{
+
+ private final ModuleModel moduleModel;
+ private final ConcurrentHashMap<String, Class<?>> classes = new ConcurrentHashMap<>();
+
+ ModuleClassLoader( ModuleModel moduleModel, ClassLoader classLoader )
+ {
+ super( classLoader );
+ this.moduleModel = moduleModel;
+ }
+
+ @Override
+ protected Class<?> findClass( String className )
+ throws ClassNotFoundException
+ {
+ try
+ {
+ Class<?> resultingClass = classes.computeIfAbsent( className, name ->
+ {
+ Predicate<ModelDescriptor> modelTypeSpecification = modelTypeSpecification( name );
+ Stream<? extends ModelDescriptor> moduleModels = concat(
+ moduleModel.visibleObjects( Visibility.module ),
+ concat(
+ moduleModel.visibleEntities( Visibility.module ),
+ concat(
+ moduleModel.visibleTransients( Visibility.module ),
+ moduleModel.visibleValues( Visibility.module )
+ )
+ )
+ ).filter( modelTypeSpecification );
+
+ Class<?> clazz = null;
+ Iterator<? extends ModelDescriptor> iterator = moduleModels.iterator();
+ if( iterator.hasNext() )
+ {
+ clazz = iterator.next().types().findFirst().orElse( null );
+
+ if( iterator.hasNext() )
+ {
+ // Ambiguous exception
+ new AmbiguousTypeException(
+ "More than one model matches the classname " + name + ":" + iterator.next()
+ );
+ }
+ }
+
+ // Check layer
+ if( clazz == null )
+ {
+ Stream<? extends ModelDescriptor> modelsInLayer1 = concat(
+ moduleModel.layer().visibleObjects( Visibility.layer ),
+ concat(
+ moduleModel.layer().visibleEntities( Visibility.layer ),
+ concat(
+ moduleModel.layer().visibleTransients( Visibility.layer ),
+ moduleModel.layer().visibleValues( Visibility.layer )
+ )
+ )
+ );
+ // TODO: What does this actually represents?? Shouldn't 'application' visible models already be handed back from lasyerInstance().visibleXyz() ??
+ Stream<? extends ModelDescriptor> modelsInLayer2 = concat(
+ moduleModel.layer().visibleObjects( Visibility.application ),
+ concat(
+ moduleModel.layer().visibleEntities( Visibility.application ),
+ concat(
+ moduleModel.layer().visibleTransients( Visibility.application ),
+ moduleModel.layer().visibleValues( Visibility.application )
+ )
+ )
+ );
+ Stream<? extends ModelDescriptor> layerModels = concat(
+ modelsInLayer1,
+ modelsInLayer2
+ ).filter( modelTypeSpecification );
+
+ Iterator<? extends ModelDescriptor> layerModelsIter = layerModels.iterator();
+ if( layerModelsIter.hasNext() )
+ {
+ clazz = layerModelsIter.next().types().findFirst().orElse( null );
+
+ if( layerModelsIter.hasNext() )
+ {
+ // Ambiguous exception
+ new AmbiguousTypeException(
+ "More than one model matches the classname " + name + ":" + layerModelsIter.next()
+ );
+ }
+ }
+ }
+
+ // Check used layers
+ if( clazz == null )
+ {
+ Stream<? extends ModelDescriptor> usedLayersModels = concat(
+ moduleModel.layer()
+ .usedLayers()
+ .layers()
+ .flatMap( layer -> layer.visibleObjects( module ) ),
+ concat(
+ moduleModel.layer()
+ .usedLayers()
+ .layers()
+ .flatMap( layer -> layer.visibleEntities( Visibility.layer ) ),
+ concat(
+ moduleModel.layer()
+ .usedLayers()
+ .layers()
+ .flatMap( layer -> layer.visibleTransients( application ) ),
+ moduleModel.layer()
+ .usedLayers()
+ .layers()
+ .flatMap( layer -> layer.visibleValues( application ) )
+ )
+ )
+ ).filter( modelTypeSpecification );
+
+ Iterator<? extends ModelDescriptor> usedLayersModelsIter = usedLayersModels.iterator();
+ if( usedLayersModelsIter.hasNext() )
+ {
+ clazz = usedLayersModelsIter.next().types().findFirst().orElse( null );
+
+ if( usedLayersModelsIter.hasNext() )
+ {
+ // Ambiguous exception
+ new AmbiguousTypeException(
+ "More than one model matches the classname " + name + ":" + usedLayersModelsIter.next()
+ );
+ }
+ }
+ }
+ return clazz;
+ } );
+ if( resultingClass == null )
+ {
+ throw new ClassNotFoundException();
+ }
+ return resultingClass;
+ }
+ catch( AmbiguousTypeException e )
+ {
+ throw new ClassNotFoundException( className, e );
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ModuleInstance.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ModuleInstance.java b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ModuleInstance.java
new file mode 100644
index 0000000..4eb9ac1
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ModuleInstance.java
@@ -0,0 +1,606 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ */
+package org.apache.polygene.runtime.structure;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import org.apache.polygene.api.activation.Activation;
+import org.apache.polygene.api.activation.ActivationEventListener;
+import org.apache.polygene.api.activation.ActivationException;
+import org.apache.polygene.api.activation.PassivationException;
+import org.apache.polygene.api.association.AssociationDescriptor;
+import org.apache.polygene.api.common.ConstructionException;
+import org.apache.polygene.api.composite.Composite;
+import org.apache.polygene.api.composite.ModelDescriptor;
+import org.apache.polygene.api.composite.NoSuchTransientException;
+import org.apache.polygene.api.composite.TransientBuilder;
+import org.apache.polygene.api.composite.TransientBuilderFactory;
+import org.apache.polygene.api.composite.TransientDescriptor;
+import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.api.identity.IdentityGenerator;
+import org.apache.polygene.api.metrics.MetricsProvider;
+import org.apache.polygene.api.object.NoSuchObjectException;
+import org.apache.polygene.api.object.ObjectDescriptor;
+import org.apache.polygene.api.object.ObjectFactory;
+import org.apache.polygene.api.property.Property;
+import org.apache.polygene.api.property.PropertyDescriptor;
+import org.apache.polygene.api.query.QueryBuilder;
+import org.apache.polygene.api.query.QueryBuilderFactory;
+import org.apache.polygene.api.service.NoSuchServiceException;
+import org.apache.polygene.api.service.ServiceFinder;
+import org.apache.polygene.api.service.ServiceReference;
+import org.apache.polygene.api.structure.LayerDescriptor;
+import org.apache.polygene.api.structure.Module;
+import org.apache.polygene.api.structure.ModuleDescriptor;
+import org.apache.polygene.api.structure.TypeLookup;
+import org.apache.polygene.api.type.HasTypes;
+import org.apache.polygene.api.unitofwork.UnitOfWorkException;
+import org.apache.polygene.api.unitofwork.UnitOfWorkFactory;
+import org.apache.polygene.api.util.NullArgumentException;
+import org.apache.polygene.api.value.NoSuchValueException;
+import org.apache.polygene.api.value.ValueBuilder;
+import org.apache.polygene.api.value.ValueBuilderFactory;
+import org.apache.polygene.api.value.ValueComposite;
+import org.apache.polygene.api.value.ValueDescriptor;
+import org.apache.polygene.api.value.ValueSerialization;
+import org.apache.polygene.api.value.ValueSerializationException;
+import org.apache.polygene.runtime.activation.ActivationDelegate;
+import org.apache.polygene.runtime.composite.FunctionStateResolver;
+import org.apache.polygene.runtime.composite.StateResolver;
+import org.apache.polygene.runtime.composite.TransientBuilderInstance;
+import org.apache.polygene.runtime.composite.TransientStateInstance;
+import org.apache.polygene.runtime.composite.UsesInstance;
+import org.apache.polygene.runtime.injection.InjectionContext;
+import org.apache.polygene.runtime.object.ObjectModel;
+import org.apache.polygene.runtime.property.PropertyInstance;
+import org.apache.polygene.runtime.property.PropertyModel;
+import org.apache.polygene.runtime.query.QueryBuilderFactoryImpl;
+import org.apache.polygene.runtime.service.ImportedServicesInstance;
+import org.apache.polygene.runtime.service.ImportedServicesModel;
+import org.apache.polygene.runtime.service.ServicesInstance;
+import org.apache.polygene.runtime.service.ServicesModel;
+import org.apache.polygene.runtime.value.ValueBuilderInstance;
+import org.apache.polygene.runtime.value.ValueBuilderWithPrototype;
+import org.apache.polygene.runtime.value.ValueBuilderWithState;
+import org.apache.polygene.runtime.value.ValueInstance;
+import org.apache.polygene.spi.entitystore.EntityStore;
+import org.apache.polygene.spi.metrics.MetricsProviderAdapter;
+import org.apache.polygene.spi.module.ModuleSpi;
+
+import static java.util.Arrays.asList;
+import static java.util.stream.Stream.concat;
+
+/**
+ * Instance of a Polygene Module. Contains the various composites for this Module.
+ */
+public class ModuleInstance
+ implements Module, ModuleSpi, Activation
+{
+ // Constructor parameters
+ private final ModuleModel model;
+ private final LayerDescriptor layer;
+ private final TypeLookup typeLookup;
+ private final ServicesInstance services;
+ private final ImportedServicesInstance importedServices;
+ // Eager instance objects
+ private final ActivationDelegate activation;
+ private final QueryBuilderFactory queryBuilderFactory;
+ // Lazy assigned on accessors
+ private EntityStore store;
+ private IdentityGenerator generator;
+ private ValueSerialization valueSerialization;
+ private MetricsProvider metrics;
+ private UnitOfWorkFactory uowf;
+
+ @SuppressWarnings( "LeakingThisInConstructor" )
+ public ModuleInstance( ModuleModel moduleModel, LayerDescriptor layer, TypeLookup typeLookup,
+ ServicesModel servicesModel, ImportedServicesModel importedServicesModel
+ )
+ {
+ // Constructor parameters
+ model = moduleModel;
+ this.layer = layer;
+ this.typeLookup = typeLookup;
+ services = servicesModel.newInstance( moduleModel );
+ importedServices = importedServicesModel.newInstance( moduleModel );
+
+ // Eager instance objects
+ activation = new ActivationDelegate( this );
+ queryBuilderFactory = new QueryBuilderFactoryImpl( this );
+
+ // Activation
+ services.registerActivationEventListener( activation );
+ importedServices.registerActivationEventListener( activation );
+ }
+
+ @Override
+ public String toString()
+ {
+ return model.toString();
+ }
+
+ @Override
+ public ModuleDescriptor descriptor()
+ {
+ return model;
+ }
+
+ // Implementation of Module
+ @Override
+ public String name()
+ {
+ return model.name();
+ }
+
+ // Implementation of MetaInfoHolder
+ @Override
+ public <T> T metaInfo( Class<T> infoType )
+ {
+ return model.metaInfo( infoType );
+ }
+
+ // Implementation of ObjectFactory
+ @Override
+ public <T> T newObject( Class<T> mixinType, Object... uses )
+ throws NoSuchObjectException
+ {
+ NullArgumentException.validateNotNull( "mixinType", mixinType );
+ ObjectDescriptor model = typeLookup.lookupObjectModel( mixinType );
+
+ if( model == null )
+ {
+ throw new NoSuchObjectException( mixinType.getName(), name(),
+ typeLookup.allObjects().flatMap( HasTypes::types ) );
+ }
+
+ InjectionContext injectionContext = new InjectionContext( model.module(), UsesInstance.EMPTY_USES.use( uses ) );
+ return mixinType.cast( ( (ObjectModel) model ).newInstance( injectionContext ) );
+ }
+
+ @Override
+ public void injectTo( Object instance, Object... uses )
+ throws ConstructionException
+ {
+ NullArgumentException.validateNotNull( "instance", instance );
+ ObjectDescriptor model = typeLookup.lookupObjectModel( instance.getClass() );
+
+ if( model == null )
+ {
+ throw new NoSuchObjectException( instance.getClass().getName(), name(),
+ typeLookup.allObjects().flatMap( HasTypes::types ) );
+ }
+
+ InjectionContext injectionContext = new InjectionContext( model.module(), UsesInstance.EMPTY_USES.use( uses ) );
+ ( (ObjectModel) model ).inject( injectionContext, instance );
+ }
+
+ // Implementation of TransientBuilderFactory
+ @Override
+ public <T> TransientBuilder<T> newTransientBuilder( Class<T> mixinType )
+ throws NoSuchTransientException
+ {
+ NullArgumentException.validateNotNull( "mixinType", mixinType );
+ TransientDescriptor model = typeLookup.lookupTransientModel( mixinType );
+
+ if( model == null )
+ {
+ throw new NoSuchTransientException( mixinType.getName(), name(), typeLookup );
+ }
+
+ Map<AccessibleObject, Property<?>> properties = new HashMap<>();
+ model.state().properties().forEach(
+ propertyModel ->
+ {
+ Property<?> property = new PropertyInstance<>( ( (PropertyModel) propertyModel ).getBuilderInfo(),
+ propertyModel.initialValue( model.module() ) );
+ properties.put( propertyModel.accessor(), property );
+ } );
+
+ TransientStateInstance state = new TransientStateInstance( properties );
+
+ return new TransientBuilderInstance<>( model, state, UsesInstance.EMPTY_USES );
+ }
+
+ @Override
+ public <T> T newTransient( final Class<T> mixinType, Object... uses )
+ throws NoSuchTransientException, ConstructionException
+ {
+ return newTransientBuilder( mixinType ).use( uses ).newInstance();
+ }
+
+ // Implementation of ValueBuilderFactory
+ @Override
+ public <T> T newValue( Class<T> mixinType )
+ throws NoSuchValueException, ConstructionException
+ {
+ return newValueBuilder( mixinType ).newInstance();
+ }
+
+ @Override
+ public <T> ValueBuilder<T> newValueBuilder( Class<T> mixinType )
+ throws NoSuchValueException
+ {
+ NullArgumentException.validateNotNull( "mixinType", mixinType );
+ ValueDescriptor compositeModelModule = typeLookup.lookupValueModel( mixinType );
+
+ if( compositeModelModule == null )
+ {
+ throw new NoSuchValueException( mixinType.getName(), name(), typeLookup );
+ }
+
+ StateResolver stateResolver = new InitialStateResolver( compositeModelModule.module() );
+ return new ValueBuilderInstance<>( compositeModelModule, this, stateResolver );
+ }
+
+ @Override
+ public <T> ValueBuilder<T> newValueBuilderWithState( Class<T> mixinType,
+ Function<PropertyDescriptor, Object> propertyFunction,
+ Function<AssociationDescriptor, EntityReference> associationFunction,
+ Function<AssociationDescriptor, Stream<EntityReference>> manyAssociationFunction,
+ Function<AssociationDescriptor, Stream<Map.Entry<String, EntityReference>>> namedAssociationFunction
+ )
+ {
+ NullArgumentException.validateNotNull( "propertyFunction", propertyFunction );
+ NullArgumentException.validateNotNull( "associationFunction", associationFunction );
+ NullArgumentException.validateNotNull( "manyAssociationFunction", manyAssociationFunction );
+ NullArgumentException.validateNotNull( "namedAssociationFunction", namedAssociationFunction );
+
+ ValueDescriptor compositeModelModule = typeLookup.lookupValueModel( mixinType );
+
+ if( compositeModelModule == null )
+ {
+ throw new NoSuchValueException( mixinType.getName(), name(), typeLookup );
+ }
+
+ StateResolver stateResolver = new FunctionStateResolver(
+ propertyFunction, associationFunction, manyAssociationFunction, namedAssociationFunction
+ );
+ return new ValueBuilderWithState<>( compositeModelModule, this, stateResolver );
+ }
+
+ private static class InitialStateResolver
+ implements StateResolver
+ {
+ private final ModuleDescriptor module;
+
+ private InitialStateResolver( ModuleDescriptor module )
+ {
+ this.module = module;
+ }
+
+ @Override
+ public Object getPropertyState( PropertyDescriptor propertyDescriptor )
+ {
+ return propertyDescriptor.initialValue( module );
+ }
+
+ @Override
+ public EntityReference getAssociationState( AssociationDescriptor associationDescriptor )
+ {
+ return null;
+ }
+
+ @Override
+ public Stream<EntityReference> getManyAssociationState( AssociationDescriptor associationDescriptor )
+ {
+ return new ArrayList<EntityReference>().stream();
+ }
+
+ @Override
+ public Stream<Map.Entry<String, EntityReference>> getNamedAssociationState( AssociationDescriptor associationDescriptor )
+ {
+ return new HashMap<String, EntityReference>().entrySet().stream();
+ }
+ }
+
+ @Override
+ @SuppressWarnings( "unchecked" )
+ public <T> ValueBuilder<T> newValueBuilderWithPrototype( T prototype )
+ {
+ NullArgumentException.validateNotNull( "prototype", prototype );
+
+ ValueInstance valueInstance = ValueInstance.valueInstanceOf( (ValueComposite) prototype );
+ Class<Composite> valueType = (Class<Composite>) valueInstance.types().findFirst().orElse( null );
+
+ ValueDescriptor model = typeLookup.lookupValueModel( valueType );
+
+ if( model == null )
+ {
+ throw new NoSuchValueException( valueType.getName(), name(), typeLookup );
+ }
+
+ return new ValueBuilderWithPrototype<>( model, this, prototype );
+ }
+
+ @Override
+ public <T> T newValueFromSerializedState( Class<T> mixinType, String serializedState )
+ throws NoSuchValueException, ConstructionException
+ {
+ NullArgumentException.validateNotNull( "mixinType", mixinType );
+ ValueDescriptor model = typeLookup.lookupValueModel( mixinType );
+
+ if( model == null )
+ {
+ throw new NoSuchValueException( mixinType.getName(), name(), typeLookup );
+ }
+
+ try
+ {
+ return valueSerialization().deserialize( model.module(), model.valueType(), serializedState );
+ }
+ catch( ValueSerializationException ex )
+ {
+ throw new ConstructionException( "Could not create value from serialized state", ex );
+ }
+ }
+
+ // Implementation of QueryBuilderFactory
+ @Override
+ public <T> QueryBuilder<T> newQueryBuilder( final Class<T> resultType )
+ {
+ return queryBuilderFactory.newQueryBuilder( resultType );
+ }
+
+ @Override
+ public <T> ServiceReference<T> findService( Class<T> serviceType )
+ throws NoSuchServiceException
+ {
+ return findService( (Type) serviceType );
+ }
+
+ @Override
+ public <T> ServiceReference<T> findService( Type serviceType )
+ {
+ ModelDescriptor serviceModel = typeLookup.lookupServiceModel( serviceType );
+ if( serviceModel == null )
+ {
+ throw new NoSuchServiceException( serviceType.getTypeName(), name(),typeLookup );
+ }
+ return findServiceReferenceInstance( serviceModel );
+ }
+
+ @Override
+ public <T> Stream<ServiceReference<T>> findServices( final Class<T> serviceType )
+ {
+ return findServices( (Type) serviceType );
+ }
+
+ @Override
+ public <T> Stream<ServiceReference<T>> findServices( final Type serviceType )
+ {
+ List<? extends ModelDescriptor> serviceModels = typeLookup.lookupServiceModels( serviceType );
+ if( serviceModels == null )
+ {
+ return Stream.empty();
+ }
+ //noinspection unchecked
+ return serviceModels.stream()
+ .map( this::findServiceReferenceInstance )
+ .filter( Objects::nonNull )
+ .filter( ref -> ref.hasType( serviceType ) )
+ .map( ref -> (ServiceReference<T>) ref );
+ }
+
+ private <T> ServiceReference<T> findServiceReferenceInstance( ModelDescriptor model )
+ {
+ ModuleInstance moduleInstanceOfModel = (ModuleInstance) model.module().instance();
+ Optional<ServiceReference<?>> candidate =
+ concat( moduleInstanceOfModel.services.references(), moduleInstanceOfModel.importedServices.references() )
+ .filter( ref -> ref.model().equals( model ) )
+ .findAny();
+ if( candidate.isPresent() )
+ {
+ ServiceReference<?> serviceReference = candidate.get();
+ return (ServiceReference<T>) serviceReference;
+ }
+ return null;
+ }
+
+ // Implementation of Activation
+ @Override
+ @SuppressWarnings( "unchecked" )
+ public void activate()
+ throws ActivationException
+ {
+ activation.activate( model.newActivatorsInstance(), asList( services, importedServices ) );
+ }
+
+ @Override
+ public void passivate()
+ throws PassivationException
+ {
+ activation.passivate();
+ }
+
+ @Override
+ public void registerActivationEventListener( ActivationEventListener listener )
+ {
+ activation.registerActivationEventListener( listener );
+ }
+
+ @Override
+ public void deregisterActivationEventListener( ActivationEventListener listener )
+ {
+ activation.deregisterActivationEventListener( listener );
+ }
+
+ // Other methods
+ ModuleModel model()
+ {
+ return model;
+ }
+
+ public LayerDescriptor layer()
+ {
+ return layer;
+ }
+
+ @Override
+ public TypeLookup typeLookup()
+ {
+ return typeLookup;
+ }
+
+ public EntityStore entityStore()
+ {
+ synchronized( this )
+ {
+ if( store == null )
+ {
+ try
+ {
+ ServiceReference<EntityStore> service = findService( EntityStore.class );
+ store = service.get();
+ }
+ catch( NoSuchServiceException e )
+ {
+ throw new UnitOfWorkException( "No EntityStore service available in module " + name() );
+ }
+ }
+ }
+ return store;
+ }
+
+ public UnitOfWorkFactory unitOfWorkFactory()
+ {
+ synchronized( this )
+ {
+ if( uowf == null )
+ {
+ try
+ {
+ ServiceReference<UnitOfWorkFactory> service = findService( UnitOfWorkFactory.class );
+ uowf = service.get();
+ }
+ catch( NoSuchServiceException e )
+ {
+ throw new UnitOfWorkException( "No UnitOfWorkFactory service available in module " + name() );
+ }
+ }
+ }
+ return uowf;
+ }
+
+ @Override
+ public ServiceFinder serviceFinder()
+ {
+ return this;
+ }
+
+ @Override
+ public ValueBuilderFactory valueBuilderFactory()
+ {
+ return this;
+ }
+
+ @Override
+ public TransientBuilderFactory transientBuilderFactory()
+ {
+ return this;
+ }
+
+ @Override
+ public ObjectFactory objectFactory()
+ {
+ return this;
+ }
+
+ public IdentityGenerator identityGenerator()
+ {
+ synchronized( this )
+ {
+ if( generator == null )
+ {
+ ServiceReference<IdentityGenerator> service = findService( IdentityGenerator.class );
+ generator = service.get();
+ }
+ return generator;
+ }
+ }
+
+ public ValueSerialization valueSerialization()
+ {
+ synchronized( this )
+ {
+ if( valueSerialization == null )
+ {
+ try
+ {
+ ServiceReference<ValueSerialization> service = findService( ValueSerialization.class );
+ valueSerialization = service.get();
+ }
+ catch( NoSuchServiceException e )
+ {
+ throw new ValueSerializationException( "No ValueSeriaservice available in module " + name() );
+ }
+ }
+ }
+ return valueSerialization;
+ }
+
+ public MetricsProvider metricsProvider()
+ {
+ synchronized( this )
+ {
+ if( metrics == null )
+ {
+ try
+ {
+ ServiceReference<MetricsProvider> service = findService( MetricsProvider.class );
+ metrics = service.get();
+ }
+ catch( NoSuchServiceException e )
+ {
+ metrics = new MetricsProviderAdapter();
+ }
+ }
+ }
+ return metrics;
+ }
+
+// public Stream<ServiceReference<?>> visibleServices( Visibility visibility )
+// {
+// return concat( services.visibleServices( visibility ),
+// importedServices.visibleServices( visibility ) );
+// }
+//
+//
+//
+// public Stream<ServiceReference<?>> findVisibleServiceTypes()
+// {
+// return concat( visibleServices( Visibility.module ),
+// concat(
+// layer().visibleServices( Visibility.layer ),
+// concat(
+// layer().visibleServices( Visibility.application ),
+// layer().usedLayers().layers().flatMap( layer -> layer.visibleServices(Visibility.application) )
+// )
+// )
+// );
+// }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ModuleModel.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ModuleModel.java b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ModuleModel.java
new file mode 100644
index 0000000..f83a2cd
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/ModuleModel.java
@@ -0,0 +1,394 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ */
+package org.apache.polygene.runtime.structure;
+
+import java.util.stream.Stream;
+import org.apache.polygene.api.activation.ActivationException;
+import org.apache.polygene.api.common.MetaInfo;
+import org.apache.polygene.api.common.Visibility;
+import org.apache.polygene.api.composite.ModelDescriptor;
+import org.apache.polygene.api.composite.TransientDescriptor;
+import org.apache.polygene.api.entity.EntityDescriptor;
+import org.apache.polygene.api.object.ObjectDescriptor;
+import org.apache.polygene.api.service.ImportedServiceDescriptor;
+import org.apache.polygene.api.service.ServiceDescriptor;
+import org.apache.polygene.api.structure.LayerDescriptor;
+import org.apache.polygene.api.structure.Module;
+import org.apache.polygene.api.structure.ModuleDescriptor;
+import org.apache.polygene.api.structure.TypeLookup;
+import org.apache.polygene.api.util.HierarchicalVisitor;
+import org.apache.polygene.api.util.VisitableHierarchy;
+import org.apache.polygene.api.value.ValueDescriptor;
+import org.apache.polygene.runtime.activation.ActivatorsInstance;
+import org.apache.polygene.runtime.activation.ActivatorsModel;
+import org.apache.polygene.runtime.composite.TransientsModel;
+import org.apache.polygene.runtime.entity.EntitiesModel;
+import org.apache.polygene.runtime.object.ObjectsModel;
+import org.apache.polygene.runtime.service.ImportedServicesModel;
+import org.apache.polygene.runtime.service.ServicesModel;
+import org.apache.polygene.runtime.value.ValuesModel;
+
+import static java.util.stream.Stream.concat;
+import static org.apache.polygene.api.common.Visibility.application;
+import static org.apache.polygene.api.common.Visibility.layer;
+import static org.apache.polygene.api.common.Visibility.module;
+
+/**
+ * JAVADOC
+ */
+public class ModuleModel
+ implements ModuleDescriptor, VisitableHierarchy<Object, Object>
+{
+ private final LayerDescriptor layerModel;
+ private final ActivatorsModel<Module> activatorsModel;
+ private final TransientsModel transientsModel;
+ private final EntitiesModel entitiesModel;
+ private final ObjectsModel objectsModel;
+ private final ValuesModel valuesModel;
+ private final ServicesModel servicesModel;
+ private final ImportedServicesModel importedServicesModel;
+ private final TypeLookupImpl typeLookup;
+ private final ClassLoader classLoader;
+
+ private final String name;
+ private final MetaInfo metaInfo;
+ private ModuleInstance moduleInstance;
+
+ public ModuleModel( String name,
+ MetaInfo metaInfo,
+ LayerDescriptor layerModel,
+ ActivatorsModel<Module> activatorsModel,
+ TransientsModel transientsModel,
+ EntitiesModel entitiesModel,
+ ObjectsModel objectsModel,
+ ValuesModel valuesModel,
+ ServicesModel servicesModel,
+ ImportedServicesModel importedServicesModel
+ )
+ {
+ this.name = name;
+ this.metaInfo = metaInfo;
+ this.layerModel = layerModel;
+ this.activatorsModel = activatorsModel;
+ this.transientsModel = transientsModel;
+ this.entitiesModel = entitiesModel;
+ this.objectsModel = objectsModel;
+ this.valuesModel = valuesModel;
+ this.servicesModel = servicesModel;
+ this.importedServicesModel = importedServicesModel;
+ typeLookup = new TypeLookupImpl( this );
+ classLoader = new ModuleClassLoader( this, Thread.currentThread().getContextClassLoader() );
+ }
+
+ @Override
+ public String name()
+ {
+ return name;
+ }
+
+ public <T> T metaInfo( Class<T> infoType )
+ {
+ return metaInfo.get( infoType );
+ }
+
+ @Override
+ public LayerDescriptor layer()
+ {
+ return layerModel;
+ }
+
+ @Override
+ public ClassLoader classLoader()
+ {
+ return classLoader;
+ }
+
+ public ActivatorsInstance<Module> newActivatorsInstance()
+ throws ActivationException
+ {
+ return new ActivatorsInstance<>( activatorsModel.newInstances() );
+ }
+
+ @Override
+ public EntityDescriptor entityDescriptor( String name )
+ {
+ try
+ {
+ Class<?> type = classLoader().loadClass( name );
+ EntityDescriptor entityModel = typeLookup.lookupEntityModel( type );
+ if( entityModel == null )
+ {
+ return null;
+ }
+ return entityModel;
+ }
+ catch( ClassNotFoundException e )
+ {
+ return null;
+ }
+ }
+
+ @Override
+ public ObjectDescriptor objectDescriptor( String typeName )
+ {
+ try
+ {
+ Class<?> type = classLoader().loadClass( typeName );
+ ObjectDescriptor objectModel = typeLookup.lookupObjectModel( type );
+ if( objectModel == null )
+ {
+ return null;
+ }
+ return objectModel;
+ }
+ catch( ClassNotFoundException e )
+ {
+ return null;
+ }
+ }
+
+ @Override
+ public TransientDescriptor transientDescriptor( String name )
+ {
+ try
+ {
+ Class<?> type = classLoader().loadClass( name );
+ TransientDescriptor transientModel = typeLookup.lookupTransientModel( type );
+ if( transientModel == null )
+ {
+ return null;
+ }
+ return transientModel;
+ }
+ catch( ClassNotFoundException e )
+ {
+ return null;
+ }
+ }
+
+ @Override
+ public ValueDescriptor valueDescriptor( String name )
+ {
+ try
+ {
+ Class<?> type = classLoader().loadClass( name );
+ ValueDescriptor valueModel = typeLookup.lookupValueModel( type );
+ if( valueModel == null )
+ {
+ return null;
+ }
+ return valueModel;
+ }
+ catch( ClassNotFoundException e )
+ {
+ return null;
+ }
+ }
+
+ @Override
+ public Module instance()
+ {
+ return moduleInstance;
+ }
+
+ @Override
+ public TypeLookup typeLookup()
+ {
+ return typeLookup;
+ }
+
+ public ModuleInstance newInstance( LayerDescriptor layerInstance )
+ {
+ moduleInstance = new ModuleInstance( this, layerInstance, typeLookup, servicesModel, importedServicesModel );
+ return moduleInstance;
+ }
+
+ @Override
+ public Stream<? extends TransientDescriptor> transientComposites()
+ {
+ return transientsModel.stream();
+ }
+
+ @Override
+ public Stream<? extends ValueDescriptor> valueComposites()
+ {
+ return valuesModel.stream();
+ }
+
+ @Override
+ public Stream<? extends ServiceDescriptor> serviceComposites()
+ {
+ return servicesModel.models();
+ }
+
+ @Override
+ public Stream<? extends EntityDescriptor> entityComposites()
+ {
+ return entitiesModel.stream();
+ }
+
+ @Override
+ public Stream<? extends ImportedServiceDescriptor> importedServices()
+ {
+ return importedServicesModel.models();
+ }
+
+ @Override
+ public Stream<? extends ObjectDescriptor> objects()
+ {
+ return objectsModel.models();
+ }
+
+ public Stream<? extends ValueDescriptor> findVisibleValueTypes()
+ {
+ return concat( visibleValues( module ),
+ concat(
+ layer().visibleValues( layer ),
+ concat(
+ layer().visibleValues( application ),
+ layer().usedLayers().layers().flatMap( layer1 -> layer1.visibleValues( application ) )
+ )
+ )
+ );
+ }
+
+ public Stream<? extends EntityDescriptor> findVisibleEntityTypes()
+ {
+ return concat( visibleEntities( module ),
+ concat(
+ layer().visibleEntities( layer ),
+ concat(
+ layer().visibleEntities( application ),
+ layer().usedLayers().layers().flatMap( layer1 -> layer1.visibleEntities( application ) )
+ )
+ )
+ );
+ }
+
+ public Stream<? extends TransientDescriptor> findVisibleTransientTypes()
+ {
+ return concat( visibleTransients( module ),
+ concat(
+ layer().visibleTransients( layer ),
+ concat(
+ layer().visibleTransients( application ),
+ layer().usedLayers()
+ .layers()
+ .flatMap( layer1 -> layer1.visibleTransients( application ) )
+ )
+ )
+ );
+ }
+
+ public Stream<? extends ModelDescriptor> findVisibleServiceTypes()
+ {
+ return concat( visibleServices( module ),
+ concat(
+ layer().visibleServices( layer ),
+ concat(
+ layer().visibleServices( application ),
+ layer().usedLayers().layers().flatMap( layer1 -> layer1.visibleServices( application ) )
+ )
+ )
+ );
+ }
+
+ public Stream<? extends ObjectDescriptor> findVisibleObjectTypes()
+ {
+ return concat( visibleObjects( module ),
+ concat(
+ layer().visibleObjects( layer ),
+ concat(
+ layer().visibleObjects( application ),
+ layer().usedLayers().layers().flatMap( layer -> layer.visibleObjects( application ) )
+ )
+ )
+ );
+ }
+
+ public Stream<? extends ObjectDescriptor> visibleObjects( Visibility visibility )
+ {
+ return objectsModel.models()
+ .filter( new Visibilitypredicate( visibility ) );
+ }
+
+ public Stream<? extends TransientDescriptor> visibleTransients( Visibility visibility )
+ {
+ return transientsModel.models()
+ .filter( new Visibilitypredicate( visibility ) );
+ }
+
+ public Stream<? extends EntityDescriptor> visibleEntities( Visibility visibility )
+ {
+ return entitiesModel.models()
+ .filter( new Visibilitypredicate( visibility ) );
+ }
+
+ public Stream<? extends ValueDescriptor> visibleValues( Visibility visibility )
+ {
+ return valuesModel.models()
+ .filter( new Visibilitypredicate( visibility ) );
+ }
+
+ public Stream<? extends ModelDescriptor> visibleServices( Visibility visibility )
+ {
+ return concat(
+ servicesModel.models()
+ .filter( new Visibilitypredicate( visibility ) ),
+ importedServicesModel.models()
+ .filter( new Visibilitypredicate( visibility ) )
+ );
+ }
+
+ @Override
+ public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> modelVisitor )
+ throws ThrowableType
+ {
+ if( modelVisitor.visitEnter( this ) )
+ {
+ if( activatorsModel.accept( modelVisitor ) )
+ {
+ if( transientsModel.accept( modelVisitor ) )
+ {
+ if( entitiesModel.accept( modelVisitor ) )
+ {
+ if( servicesModel.accept( modelVisitor ) )
+ {
+ if( importedServicesModel.accept( modelVisitor ) )
+ {
+ if( objectsModel.accept( modelVisitor ) )
+ {
+ valuesModel.accept( modelVisitor );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return modelVisitor.visitLeave( this );
+ }
+
+ @Override
+ public String toString()
+ {
+ return name;
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/1c722f44/core/runtime/src/main/java/org/apache/polygene/runtime/structure/TypeLookupImpl.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/polygene/runtime/structure/TypeLookupImpl.java b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/TypeLookupImpl.java
new file mode 100644
index 0000000..9df92c9
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/polygene/runtime/structure/TypeLookupImpl.java
@@ -0,0 +1,543 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ */
+package org.apache.polygene.runtime.structure;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.WildcardType;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+import org.apache.polygene.api.common.Visibility;
+import org.apache.polygene.api.composite.AmbiguousTypeException;
+import org.apache.polygene.api.composite.ModelDescriptor;
+import org.apache.polygene.api.composite.TransientDescriptor;
+import org.apache.polygene.api.entity.EntityDescriptor;
+import org.apache.polygene.api.object.ObjectDescriptor;
+import org.apache.polygene.api.structure.ModuleDescriptor;
+import org.apache.polygene.api.structure.TypeLookup;
+import org.apache.polygene.api.type.HasTypes;
+import org.apache.polygene.api.value.ValueDescriptor;
+
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Stream.concat;
+import static org.apache.polygene.api.common.Visibility.application;
+import static org.apache.polygene.api.common.Visibility.layer;
+import static org.apache.polygene.api.util.Classes.interfacesOf;
+
+/**
+ * Central place for Composite Type lookups.
+ */
+class TypeLookupImpl
+ implements TypeLookup
+{
+ private final LazyValue<List<ObjectDescriptor>> allObjects;
+ private final LazyValue<List<TransientDescriptor>> allTransients;
+ private final LazyValue<List<ValueDescriptor>> allValues;
+ private final LazyValue<List<EntityDescriptor>> allEntities;
+ private final LazyValue<List<? extends ModelDescriptor>> allServices;
+ private final ConcurrentHashMap<Class<?>, ObjectDescriptor> objectModels;
+ private final ConcurrentHashMap<Class<?>, TransientDescriptor> transientModels;
+ private final ConcurrentHashMap<Class<?>, ValueDescriptor> valueModels;
+ private final ConcurrentHashMap<Class<?>, List<EntityDescriptor>> entityModels;
+ private final ConcurrentHashMap<Class<?>, EntityDescriptor> unambiguousEntityModels;
+ private final ConcurrentHashMap<Type, ModelDescriptor> serviceModels;
+ private final ConcurrentHashMap<Type, List<? extends ModelDescriptor>> servicesReferences;
+
+ private final ModuleDescriptor moduleModel;
+
+ /**
+ * Create a new TypeLookup bound to the given ModuleModel.
+ *
+ * @param module ModuleModel bound to this TypeLookup
+ */
+ TypeLookupImpl( ModuleModel module )
+ {
+ moduleModel = module;
+
+ // Instance caches
+ allObjects = new LazyValue<>();
+ allTransients = new LazyValue<>();
+ allValues = new LazyValue<>();
+ allEntities = new LazyValue<>();
+ allServices = new LazyValue<>();
+ objectModels = new ConcurrentHashMap<>();
+ transientModels = new ConcurrentHashMap<>();
+ valueModels = new ConcurrentHashMap<>();
+ entityModels = new ConcurrentHashMap<>();
+ unambiguousEntityModels = new ConcurrentHashMap<>();
+ serviceModels = new ConcurrentHashMap<>();
+ servicesReferences = new ConcurrentHashMap<>();
+ }
+
+ @Override
+ public ObjectDescriptor lookupObjectModel( final Class<?> type )
+ {
+ return objectModels.computeIfAbsent( type, key ->
+ {
+ List<? extends ObjectDescriptor> allModels = getAllObjects();
+ ObjectDescriptor model = ambiguityMatching( key, allModels, new ExactTypeMatching<>( key ) );
+ if( model == null )
+ {
+ model = ambiguityMatching( key, allModels, new AssignableFromTypeMatching<>( key ) );
+ }
+ return model;
+ } );
+ }
+
+ @Override
+ public TransientDescriptor lookupTransientModel( final Class<?> type )
+ {
+ return transientModels.computeIfAbsent( type, key ->
+ {
+ List<? extends TransientDescriptor> allModels = getAllTransients();
+ TransientDescriptor model = ambiguityMatching( key, allModels, new ExactTypeMatching<>( key ) );
+ if( model == null )
+ {
+ model = ambiguityMatching( key, allModels, new AssignableFromTypeMatching<>( key ) );
+ }
+ return model;
+ } );
+ }
+
+ @Override
+ public ValueDescriptor lookupValueModel( final Class<?> type )
+ {
+ return valueModels.computeIfAbsent( type, key ->
+ {
+ List<? extends ValueDescriptor> allModels = getAllValues();
+ ValueDescriptor model = ambiguityMatching( key, allModels, new ExactTypeMatching<>( key ) );
+ if( model == null )
+ {
+ model = ambiguityMatching( key, allModels, new AssignableFromTypeMatching<>( key ) );
+ }
+ return model;
+ } );
+ }
+
+ @Override
+ public EntityDescriptor lookupEntityModel( final Class<?> type )
+ {
+ return unambiguousEntityModels.computeIfAbsent( type, key ->
+ {
+ List<? extends EntityDescriptor> allModels = getAllEntities();
+ EntityDescriptor model = ambiguityMatching( key, allModels, new ExactTypeMatching<>( key ) );
+ if( model == null )
+ {
+ model = ambiguityMatching( key, allModels, new AssignableFromTypeMatching<>( key ) );
+ }
+ return model;
+ } );
+ }
+
+ @Override
+ public List<EntityDescriptor> lookupEntityModels( final Class type )
+ {
+ return entityModels.computeIfAbsent(
+ type,
+ key -> new TypeMatchesSelector<EntityDescriptor>( key ).selectFrom( allEntities() ) );
+ }
+
+ @Override
+ public ModelDescriptor lookupServiceModel( Type serviceType )
+ {
+ return serviceModels.computeIfAbsent(
+ serviceType,
+ key -> new BestTypeMatchSelector<ModelDescriptor>( key ).selectFrom( allServices() )
+ .bestMatchOrElse( null ) );
+ }
+
+ @Override
+ public List<? extends ModelDescriptor> lookupServiceModels( final Type type )
+ {
+ return servicesReferences.computeIfAbsent(
+ type,
+ key -> new TypeMatchesSelector<ModelDescriptor>( key ).selectFrom( allServices() ) );
+ }
+
+ @Override
+ public Stream<ObjectDescriptor> allObjects()
+ {
+ return getAllObjects().stream();
+ }
+
+ private List<ObjectDescriptor> getAllObjects()
+ {
+ return allObjects.computeIfAbsent(
+ () -> concat( moduleModel.objects(),
+ concat(
+ concat(
+ moduleModel.layer().visibleObjects( layer ),
+ moduleModel.layer()
+ .visibleObjects( application )
+ ),
+ moduleModel.layer()
+ .usedLayers()
+ .layers()
+ .flatMap( layer -> layer.visibleObjects( application ) )
+ )
+ ).collect( toList() )
+ );
+ }
+
+ @Override
+ public Stream<TransientDescriptor> allTransients()
+ {
+ return getAllTransients().stream();
+ }
+
+ private List<TransientDescriptor> getAllTransients()
+ {
+ return allTransients.computeIfAbsent(
+ () -> concat( moduleModel.transientComposites(),
+ concat(
+ concat(
+ moduleModel.layer().visibleTransients( layer ),
+ moduleModel.layer().visibleTransients( application )
+ ),
+ moduleModel.layer()
+ .usedLayers()
+ .layers()
+ .flatMap( layer -> layer.visibleTransients( application ) )
+ )
+ ).collect( toList() )
+ );
+ }
+
+ @Override
+ public Stream<ValueDescriptor> allValues()
+ {
+ return getAllValues().stream();
+ }
+
+ private List<ValueDescriptor> getAllValues()
+ {
+ return allValues.computeIfAbsent(
+ () -> concat( moduleModel.valueComposites(),
+ concat(
+ concat( moduleModel.layer().visibleValues( layer ),
+ moduleModel.layer().visibleValues( application )
+ ),
+ moduleModel.layer()
+ .usedLayers()
+ .layers()
+ .flatMap( layer1 -> layer1.visibleValues( application ) )
+ )
+ ).collect( toList() )
+ );
+ }
+
+ @Override
+ public Stream<EntityDescriptor> allEntities()
+ {
+ return getAllEntities().stream();
+ }
+
+ private List<EntityDescriptor> getAllEntities()
+ {
+ return allEntities.computeIfAbsent(
+ () -> concat( moduleModel.entityComposites(),
+ concat(
+ concat(
+ moduleModel.layer().visibleEntities( layer ),
+ moduleModel.layer().visibleEntities( application )
+ ),
+ moduleModel.layer()
+ .usedLayers()
+ .layers()
+ .flatMap( layer -> layer.visibleEntities( application ) )
+ )
+ ).collect( toList() )
+ );
+ }
+
+ @Override
+ public Stream<? extends ModelDescriptor> allServices()
+ {
+ return getAllServices().stream();
+ }
+
+ private List<? extends ModelDescriptor> getAllServices()
+ {
+ return allServices.computeIfAbsent(
+ () -> concat(
+ concat( moduleModel.serviceComposites(),
+ concat(
+ concat(
+ moduleModel.layer().visibleServices( layer ),
+ moduleModel.layer().visibleServices( application )
+ ),
+ moduleModel.layer()
+ .usedLayers()
+ .layers()
+ .flatMap( layer -> layer.visibleServices( application ) )
+ )
+ ),
+ concat( moduleModel.importedServices(),
+ concat(
+ concat(
+ moduleModel.layer().visibleServices( layer ),
+ moduleModel.layer().visibleServices( application )
+ ),
+ moduleModel.layer()
+ .usedLayers()
+ .layers()
+ .flatMap( layer -> layer.visibleServices( application ) )
+ )
+ )
+ ).collect( toList() )
+ );
+ }
+
+ private static <T extends ModelDescriptor> T ambiguityMatching(
+ Class type,
+ List<T> modelModules,
+ TypeMatching<T> matching
+ )
+ {
+ List<T> models = modelModules.stream()
+ .filter( matching.and( new SameVisibility<>() ) )
+ .distinct()
+ .collect( toList() );
+ if( models.size() > 1 )
+ {
+ throw new AmbiguousTypeException( "More than one type matches " + type.getName() + ": " + models + "]" );
+ }
+ if( models.isEmpty() )
+ {
+ return null;
+ }
+ return models.get( 0 );
+ }
+
+ private static abstract class TypeMatching<T extends HasTypes>
+ implements Predicate<T>
+ {
+ protected final Type lookedUpType;
+
+ protected TypeMatching( Type lookedUpType )
+ {
+ this.lookedUpType = lookedUpType;
+ }
+
+ @Override
+ public final boolean test( T model )
+ {
+ if( lookedUpType instanceof Class )
+ {
+ return model.types().anyMatch( checkMatch( lookedUpType ) );
+ }
+ else
+ {
+ if( lookedUpType instanceof ParameterizedType )
+ {
+ // Foo<Bar> check
+ // First check Foo
+ ParameterizedType parameterizedType = (ParameterizedType) lookedUpType;
+ Type rawType = parameterizedType.getRawType();
+ if( model.types().noneMatch( checkMatch( rawType ) ) )
+ {
+ return false;
+ }
+ // Then check Bar
+ return interfacesOf( model.types() ).anyMatch( intf -> intf.equals( lookedUpType ) );
+ }
+ else if( lookedUpType instanceof WildcardType )
+ {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ protected abstract Predicate<Type> checkMatch( Type matchTo );
+ }
+
+ private static class ExactTypeMatching<T extends HasTypes> extends TypeMatching<T>
+ {
+ private ExactTypeMatching( Type lookedUpType )
+ {
+ super( lookedUpType );
+ }
+
+ protected Predicate<Type> checkMatch( Type matchTo )
+ {
+ return matchTo::equals;
+ }
+ }
+
+ private static class AssignableFromTypeMatching<T extends HasTypes> extends TypeMatching<T>
+ {
+ private AssignableFromTypeMatching( Type lookedUpType )
+ {
+ super( lookedUpType );
+ }
+
+ protected Predicate<Type> checkMatch( Type matchTo )
+ {
+ // TODO; what to do if there is ParameterizedType here?? Now set to ClassCastException and see if anything surfaces
+// if( matchTo instanceof Class )
+ {
+ Class<?> clazz = (Class<?>) matchTo;
+ return candidate -> !candidate.equals( matchTo ) && clazz.isAssignableFrom( (Class<?>) candidate );
+ }
+// return candidate -> candidate.equals( matchTo );
+ }
+ }
+
+ /**
+ * Selects descriptors by combining {@link ExactTypeMatching} and {@link AssignableFromTypeMatching}.
+ *
+ * Selected descriptors are sorted, exact matches first, assignable ones second.
+ * Other than that, original order is preserved.
+ *
+ * <code>
+ * [ assignable1, matching1, assignable2, assignable3, matching2, non-matching-nor-assignable ]
+ * </code>
+ * results in
+ * <code>
+ * [ matching1, matching2, assignable1, assignable2, assignable3 ]
+ * </code>
+ *
+ * @param <T> Descriptor type
+ */
+ private static class TypeMatchesSelector<T extends HasTypes> extends ArrayList<T>
+ {
+ private final ExactTypeMatching<T> exactMatchPredicate;
+ private final AssignableFromTypeMatching<T> assignablePredicate;
+ private Integer lastMatchIndex;
+
+ private TypeMatchesSelector( Type type )
+ {
+ this.exactMatchPredicate = new ExactTypeMatching<>( type );
+ this.assignablePredicate = new AssignableFromTypeMatching<>( type );
+ }
+
+ List<T> selectFrom( Stream<? extends T> candidates )
+ {
+ candidates.forEach( this::addDescriptor );
+ return this;
+ }
+
+ private void addDescriptor( T descriptor )
+ {
+ if( contains( descriptor ) )
+ {
+ return;
+ }
+ if( exactMatchPredicate.test( descriptor ) )
+ {
+ Integer nextMatchIndex = lastMatchIndex == null ? 0 : lastMatchIndex + 1;
+ add( nextMatchIndex, descriptor );
+ lastMatchIndex = nextMatchIndex;
+ }
+ else if( assignablePredicate.test( descriptor ) )
+ {
+ add( descriptor );
+ }
+ }
+
+ boolean containsExactMatches()
+ {
+ return lastMatchIndex != null;
+ }
+ }
+
+ /**
+ * Selects the best matching descriptor by combining {@link ExactTypeMatching} and {@link AssignableFromTypeMatching}.
+ *
+ * Selected descriptor is the first exact match if it exists, the first assignable otherwise.
+ *
+ * @param <T> Descriptor type
+ */
+ private static class BestTypeMatchSelector<T extends HasTypes>
+ {
+ private TypeMatchesSelector<T> descriptors;
+
+ BestTypeMatchSelector( Type type )
+ {
+ this.descriptors = new TypeMatchesSelector<>( type );
+ }
+
+ BestTypeMatchSelector<T> selectFrom( Stream<? extends T> candidates )
+ {
+ candidates.forEach( this::addDescriptor );
+ return this;
+ }
+
+ T bestMatchOrElse( T or )
+ {
+ return !descriptors.isEmpty() ? descriptors.get( 0 ) : or;
+ }
+
+ private void addDescriptor( T descriptor )
+ {
+ // Until an exact match is found, even if we already found assignable ones,
+ // keep selecting in case the last element is an exact match.
+ if( !descriptors.containsExactMatches() )
+ {
+ descriptors.addDescriptor( descriptor );
+ }
+ }
+ }
+
+ /**
+ * This Predicate will filter out all Models that doesn't have the same visibility as the first one.
+ */
+ private static class SameVisibility<T extends ModelDescriptor>
+ implements Predicate<T>
+ {
+ private Visibility current = null;
+
+ @Override
+ public boolean test( T model )
+ {
+ if( current == null )
+ {
+ current = model.visibility();
+ return true;
+ }
+ return current == model.visibility();
+ }
+ }
+
+ private static class LazyValue<T>
+ {
+ private volatile T value;
+
+ public T computeIfAbsent( Supplier<T> supplier )
+ {
+ if( value == null )
+ {
+ synchronized( this )
+ {
+ if( value == null )
+ {
+ value = supplier.get();
+ }
+ }
+ }
+ return value;
+ }
+ }
+}