http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/query/IterableQuerySource.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/query/IterableQuerySource.java b/core/runtime/src/main/java/org/apache/zest/runtime/query/IterableQuerySource.java new file mode 100644 index 0000000..41ec961 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/query/IterableQuerySource.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2008, Rickard Ãberg. All Rights Reserved. + * + * Licensed 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.zest.runtime.query; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import org.apache.zest.api.composite.Composite; +import org.apache.zest.api.property.Property; +import org.apache.zest.api.query.grammar.OrderBy; +import org.apache.zest.api.util.Classes; +import org.apache.zest.functional.Iterables; +import org.apache.zest.functional.Specification; +import org.apache.zest.functional.Specifications; +import org.apache.zest.spi.query.QuerySource; + +/** + * JAVADOC + */ +public class IterableQuerySource + implements QuerySource +{ + private final Iterable iterable; + + /** + * Constructor. + * + * @param iterable iterable + */ + @SuppressWarnings( "raw" ) + IterableQuerySource( final Iterable iterable ) + { + this.iterable = iterable; + } + + @Override + public <T> T find( Class<T> resultType, + Specification<Composite> whereClause, + Iterable<OrderBy> orderBySegments, + Integer firstResult, + Integer maxResults, + Map<String, Object> variables + ) + { + final Iterator<T> iterator = iterator( resultType, whereClause, orderBySegments, firstResult, maxResults, variables ); + if( iterator.hasNext() ) + { + return iterator.next(); + } + return null; + } + + @Override + public <T> long count( Class<T> resultType, + Specification<Composite> whereClause, + Iterable<OrderBy> orderBySegments, + Integer firstResult, + Integer maxResults, + Map<String, Object> variables + ) + { + return list( resultType, whereClause, orderBySegments, firstResult, maxResults, variables ).size(); + } + + @Override + public <T> Iterator<T> iterator( Class<T> resultType, + Specification<Composite> whereClause, + Iterable<OrderBy> orderBySegments, + Integer firstResult, + Integer maxResults, + Map<String, Object> variables + ) + { + return list( resultType, whereClause, orderBySegments, firstResult, maxResults, variables ).iterator(); + } + + @SuppressWarnings( {"raw", "unchecked"} ) + private <T> List<T> list( Class<T> resultType, + Specification<Composite> whereClause, + Iterable<OrderBy> orderBySegments, + Integer firstResult, + Integer maxResults, + Map<String, Object> variables + ) + { + // Ensure it's a list first + List<T> list = filter( resultType, whereClause ); + + // Order list + if( orderBySegments != null ) + { + // Sort it + Collections.sort( list, new OrderByComparator( orderBySegments ) ); + } + + // Cut results + if( firstResult != null ) + { + if( firstResult > list.size() ) + { + return Collections.emptyList(); + } + + int toIdx; + if( maxResults != null ) + { + toIdx = Math.min( firstResult + maxResults, list.size() ); + } + else + { + toIdx = list.size(); + } + + list = list.subList( firstResult, toIdx ); + } + else + { + int toIdx; + if( maxResults != null ) + { + toIdx = Math.min( maxResults, list.size() ); + } + else + { + toIdx = list.size(); + } + + list = list.subList( 0, toIdx ); + } + + return list; + } + + @SuppressWarnings( {"raw", "unchecked"} ) + private <T> List<T> filter( Class<T> resultType, Specification whereClause ) + { + if( whereClause == null ) + { + return Iterables.toList( Iterables.filter( Classes.instanceOf( resultType ), iterable ) ); + } + else + { + return Iterables.toList( Iterables.filter( Specifications.and( Classes.instanceOf( resultType ), whereClause ), iterable ) ); + } + } + + @Override + public String toString() + { + return "IterableQuerySource{" + iterable + '}'; + } + + private static class OrderByComparator<T extends Composite> + implements Comparator<T> + { + + private final Iterable<OrderBy> orderBySegments; + + private OrderByComparator( Iterable<OrderBy> orderBySegments ) + { + this.orderBySegments = orderBySegments; + } + + @Override + @SuppressWarnings( {"raw", "unchecked"} ) + public int compare( T o1, T o2 ) + { + for( OrderBy orderBySegment : orderBySegments ) + { + try + { + final Property prop1 = orderBySegment.property().map( o1 ); + final Property prop2 = orderBySegment.property().map( o2 ); + if( prop1 == null || prop2 == null ) + { + if( prop1 == null && prop2 == null ) + { + return 0; + } + else if( prop1 != null ) + { + return 1; + } + return -1; + } + final Object value1 = prop1.get(); + final Object value2 = prop2.get(); + if( value1 == null || value2 == null ) + { + if( value1 == null && value2 == null ) + { + return 0; + } + else if( value1 != null ) + { + return 1; + } + return -1; + } + if( value1 instanceof Comparable ) + { + int result = ( (Comparable) value1 ).compareTo( value2 ); + if( result != 0 ) + { + if( orderBySegment.order() == OrderBy.Order.ASCENDING ) + { + return result; + } + else + { + return -result; + } + } + } + } + catch( Exception e ) + { + return 0; + } + } + + return 0; + } + } +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/query/QueryBuilderFactoryImpl.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/query/QueryBuilderFactoryImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/query/QueryBuilderFactoryImpl.java new file mode 100644 index 0000000..8bc93b3 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/query/QueryBuilderFactoryImpl.java @@ -0,0 +1,68 @@ +/* + * Copyright 2007-2009 Niclas Hedhman. + * Copyright 2008 Alin Dreghiciu. + * + * Licensed 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.zest.runtime.query; + +import org.apache.zest.api.query.NotQueryableException; +import org.apache.zest.api.query.QueryBuilder; +import org.apache.zest.api.query.QueryBuilderFactory; +import org.apache.zest.api.service.NoSuchServiceException; +import org.apache.zest.api.service.ServiceFinder; +import org.apache.zest.api.service.ServiceReference; +import org.apache.zest.api.util.NullArgumentException; +import org.apache.zest.spi.query.EntityFinder; + +/** + * Default implementation of {@link QueryBuilderFactory} + */ +public final class QueryBuilderFactoryImpl + implements QueryBuilderFactory +{ + private ServiceFinder finder; + + /** + * Constructor. + * + * @param finder The ServiceFinder of the Module this QueryBuilderFactory belongs to. + */ + public QueryBuilderFactoryImpl( ServiceFinder finder ) + { + NullArgumentException.validateNotNull( "ServiceFinder", finder ); + this.finder = finder; + } + + /** + * @see QueryBuilderFactory#newQueryBuilder(Class) + */ + @Override + public <T> QueryBuilder<T> newQueryBuilder( final Class<T> resultType ) + { + NotQueryableException.throwIfNotQueryable( resultType ); + + final ServiceReference<EntityFinder> serviceReference; + try + { + serviceReference = finder.findService( EntityFinder.class ); + return new QueryBuilderImpl<T>( serviceReference.get(), resultType, null ); + } + catch( NoSuchServiceException e ) + { + return new QueryBuilderImpl<T>( null, resultType, null ); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/query/QueryBuilderImpl.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/query/QueryBuilderImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/query/QueryBuilderImpl.java new file mode 100644 index 0000000..67ab342 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/query/QueryBuilderImpl.java @@ -0,0 +1,95 @@ +/* + * Copyright 2007-2009 Niclas Hedhman. + * Copyright 2008 Alin Dreghiciu. + * + * Licensed 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.zest.runtime.query; + +import org.apache.zest.api.composite.Composite; +import org.apache.zest.api.query.Query; +import org.apache.zest.api.query.QueryBuilder; +import org.apache.zest.api.query.QueryExpressions; +import org.apache.zest.functional.Specification; +import org.apache.zest.spi.query.EntityFinder; +import org.apache.zest.spi.query.QueryBuilderSPI; +import org.apache.zest.spi.query.QuerySource; + +/** + * Default implementation of {@link QueryBuilder} + */ +final class QueryBuilderImpl<T> + implements QueryBuilder<T>, QueryBuilderSPI<T> +{ + + /** + * Entity finder to be used to locate entities. + */ + private final EntityFinder entityFinder; + + /** + * Type of queried entities. + */ + private final Class<T> resultType; + /** + * Where clause. + */ + private final Specification<Composite> whereClause; + + /** + * Constructor. + * + * @param entityFinder entity finder to be used to locate entities; canot be null + * @param resultType type of queried entities; cannot be null + * @param whereClause current where-clause + */ + QueryBuilderImpl( final EntityFinder entityFinder, + final Class<T> resultType, + final Specification<Composite> whereClause + ) + { + this.entityFinder = entityFinder; + this.resultType = resultType; + this.whereClause = whereClause; + } + + @Override + @SuppressWarnings( "unchecked" ) + public QueryBuilder<T> where( Specification<Composite> specification ) + { + if( specification == null ) + { + throw new IllegalArgumentException( "Where clause cannot be null" ); + } + if( this.whereClause != null ) + { + specification = QueryExpressions.and( this.whereClause, specification ); + } + return new QueryBuilderImpl<>( entityFinder, resultType, specification ); + } + + @Override + public Query<T> newQuery( Iterable<T> iterable ) + { + return new QueryImpl<>( resultType, whereClause, new IterableQuerySource( iterable ) ); + } + + // SPI + @Override + public Query<T> newQuery( QuerySource querySource ) + { + return new QueryImpl<>( resultType, whereClause, querySource ); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/query/QueryImpl.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/query/QueryImpl.java b/core/runtime/src/main/java/org/apache/zest/runtime/query/QueryImpl.java new file mode 100644 index 0000000..59ebb5d --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/query/QueryImpl.java @@ -0,0 +1,213 @@ +/* + * Copyright 2007 Niclas Hedhman. + * Copyright 2008 Alin Dreghiciu. + * + * Licensed 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.zest.runtime.query; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import org.apache.zest.api.composite.Composite; +import org.apache.zest.api.property.Property; +import org.apache.zest.api.query.Query; +import org.apache.zest.api.query.QueryExecutionException; +import org.apache.zest.api.query.QueryExpressions; +import org.apache.zest.api.query.grammar.OrderBy; +import org.apache.zest.functional.Iterables; +import org.apache.zest.functional.Specification; +import org.apache.zest.spi.query.QuerySource; + +/** + * Default implementation of {@link org.apache.zest.api.query.Query}. + */ +/* package */ class QueryImpl<T> + implements Query<T> +{ + private static final long serialVersionUID = 1L; + + /** + * Type of queried entities. + */ + private final Class<T> resultType; + /** + * Where clause. + */ + private final Specification<Composite> whereClause; + private QuerySource querySource; + /** + * Order by clause segments. + */ + private Iterable<OrderBy> orderBySegments; + /** + * First result to be returned. + */ + private Integer firstResult; + /** + * Maximum number of results to be returned. + */ + private Integer maxResults; + /** + * Mapping between variable name and variable values. + */ + private Map<String, Object> variables; + + /** + * Constructor. + * + * @param resultType type of queried entities; cannot be null + * @param whereClause where clause + */ + /* package */ QueryImpl( final Class<T> resultType, + final Specification<Composite> whereClause, + final QuerySource querySource + ) + { + this.resultType = resultType; + this.whereClause = whereClause; + this.querySource = querySource; + } + + /** + * @see org.apache.zest.api.query.Query#orderBy(org.apache.zest.api.query.grammar.OrderBy[]) + */ + @Override + public Query<T> orderBy( final OrderBy... segments ) + { + orderBySegments = Iterables.iterable( segments ); + return this; + } + + /** + * @see org.apache.zest.api.query.Query#orderBy(org.apache.zest.api.property.Property, org.apache.zest.api.query.grammar.OrderBy.Order) + */ + @Override + public Query<T> orderBy( Property<?> property, OrderBy.Order order ) + { + if( orderBySegments == null ) + { + orderBySegments = Iterables.iterable( new OrderBy( QueryExpressions.property( property ), order ) ); + } + else + { + orderBySegments = Iterables.append( new OrderBy( QueryExpressions.property( property ), order ), orderBySegments ); + } + return this; + } + + /** + * @see org.apache.zest.api.query.Query#orderBy(org.apache.zest.api.property.Property) + */ + @Override + public Query<T> orderBy( Property<?> property ) + { + orderBy( property, OrderBy.Order.ASCENDING ); + return this; + } + + /** + * @see org.apache.zest.api.query.Query#firstResult(int) + */ + @Override + public Query<T> firstResult( int firstResult ) + { + this.firstResult = firstResult; + return this; + } + + /** + * @see org.apache.zest.api.query.Query#maxResults(int) + */ + @Override + public Query<T> maxResults( int maxResults ) + { + this.maxResults = maxResults; + return this; + } + + /** + * @see org.apache.zest.api.query.Query#setVariable(String, Object) + */ + @SuppressWarnings( "unchecked" ) + @Override + public Query<T> setVariable( final String name, final Object value ) + { + if( variables == null ) + { + variables = new HashMap<String, Object>(); + } + variables.put( name, value ); + + return this; + } + + /** + * @see org.apache.zest.api.query.Query#getVariable(String) + */ + @SuppressWarnings( "unchecked" ) + @Override + public <V> V getVariable( final String name ) + { + if( variables == null ) + { + return null; + } + else + { + return (V) variables.get( name ); + } + } + + @Override + public Class<T> resultType() + { + return resultType; + } + + @Override + public T find() + throws QueryExecutionException + { + return querySource.find( resultType, whereClause, orderBySegments, firstResult, maxResults, variables ); + } + + @Override + public long count() + throws QueryExecutionException + { + return querySource.count( resultType, whereClause, orderBySegments, firstResult, maxResults, variables ); + } + + @Override + public Iterator<T> iterator() + { + return querySource.iterator( resultType, whereClause, orderBySegments, firstResult, maxResults, variables ); + } + + @Override + public String toString() + { + return "Query{" + + " FROM " + querySource + + " WHERE " + whereClause + + ( orderBySegments != null ? " ORDER BY " + orderBySegments : "" ) + + ( firstResult != null ? " FIRST " + firstResult : "" ) + + ( maxResults != null ? " MAX " + maxResults : "" ) + + " EXPECT " + resultType + + ( variables != null ? " WITH VARIABLES " + variables : "" ) + + '}'; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServiceInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServiceInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServiceInstance.java new file mode 100644 index 0000000..b63bf11 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServiceInstance.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2007, Rickard Ãberg. All Rights Reserved. + * Copyright (c) 2012, Paul Merlin. + * + * Licensed 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.zest.runtime.service; + +import org.apache.zest.api.activation.Activation; +import org.apache.zest.api.activation.ActivationException; +import org.apache.zest.api.activation.PassivationException; +import org.apache.zest.api.service.ServiceImporter; + +/** + * JAVADOC + */ +public final class ImportedServiceInstance<T> + implements Activation +{ + private final T instance; + private final ServiceImporter<T> importer; + + public ImportedServiceInstance( T instance, ServiceImporter<T> importer ) + { + this.importer = importer; + this.instance = instance; + } + + public T instance() + { + return instance; + } + + public ServiceImporter importer() + { + return importer; + } + + public boolean isAvailable() + { + return importer.isAvailable( instance ); + } + + @Override + public void activate() + throws ActivationException + { + // NOOP + } + + @Override + public void passivate() + throws PassivationException + { + // NOOP + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServiceModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServiceModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServiceModel.java new file mode 100644 index 0000000..669010d --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServiceModel.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2008-2011, Rickard Ãberg. All Rights Reserved. + * Copyright (c) 2008-2013, Niclas Hedhman. All Rights Reserved. + * Copyright (c) 2012-2014, Paul Merlin. All Rights Reserved. + * + * Licensed 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.zest.runtime.service; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import org.apache.zest.api.common.MetaInfo; +import org.apache.zest.api.common.Visibility; +import org.apache.zest.api.service.ImportedServiceDescriptor; +import org.apache.zest.api.service.ServiceImporter; +import org.apache.zest.api.service.ServiceImporterException; +import org.apache.zest.api.structure.Module; +import org.apache.zest.functional.HierarchicalVisitor; +import org.apache.zest.functional.VisitableHierarchy; +import org.apache.zest.runtime.activation.ActivatorsInstance; +import org.apache.zest.runtime.activation.ActivatorsModel; + +import static org.apache.zest.functional.Iterables.iterable; + +/** + * JAVADOC + */ +public final class ImportedServiceModel + implements ImportedServiceDescriptor, VisitableHierarchy<Object, Object> +{ + private final Class<?> type; + private final Visibility visibility; + @SuppressWarnings( "raw" ) + private final Class<? extends ServiceImporter> serviceImporter; + private final String identity; + private final boolean importOnStartup; + private final MetaInfo metaInfo; + private final ActivatorsModel<?> activatorsModel; + private final String moduleName; + + @SuppressWarnings( "raw" ) + public ImportedServiceModel( Class serviceType, + Visibility visibility, + Class<? extends ServiceImporter> serviceImporter, + String identity, + boolean importOnStartup, + MetaInfo metaInfo, + ActivatorsModel<?> activatorsModel, + String moduleName + ) + { + type = serviceType; + this.visibility = visibility; + this.serviceImporter = serviceImporter; + this.identity = identity; + this.importOnStartup = importOnStartup; + this.metaInfo = metaInfo; + this.activatorsModel = activatorsModel; + this.moduleName = moduleName; + } + + public boolean isImportOnStartup() + { + return importOnStartup; + } + + @Override + @SuppressWarnings( "unchecked" ) + public Iterable<Class<?>> types() + { + Iterable<? extends Class<?>> iterable = iterable( type ); + return (Iterable<Class<?>>) iterable; + } + + @Override + public Visibility visibility() + { + return visibility; + } + + @Override + public <T> T metaInfo( Class<T> infoType ) + { + return metaInfo.get( infoType ); + } + + @Override + @SuppressWarnings( "raw" ) + public Class<? extends ServiceImporter> serviceImporter() + { + return serviceImporter; + } + + @Override + public Class<?> type() + { + return type; + } + + @Override + public String identity() + { + return identity; + } + + public String moduleName() + { + return moduleName; + } + + @SuppressWarnings( {"raw", "unchecked"} ) + public ActivatorsInstance<?> newActivatorsInstance( Module module ) + throws Exception + { + return new ActivatorsInstance( activatorsModel.newInstances( module ) ); + } + + @Override + public boolean isAssignableTo( Class<?> type ) + { + return this.type.isAssignableFrom( type ); + } + + @Override + public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor ) + throws ThrowableType + { + if( visitor.visitEnter( this ) ) + { + activatorsModel.accept( visitor ); + } + return visitor.visitLeave( this ); + } + + @SuppressWarnings( {"raw", "unchecked"} ) + public <T> ImportedServiceInstance<T> importInstance( Module module ) + { + ServiceImporter importer = module.newObject( serviceImporter ); + try + { + T instance = (T) importer.importService( this ); + return new ImportedServiceInstance<>( instance, importer ); + } + catch( ServiceImporterException e ) + { + throw e; + } + catch( Exception e ) + { + throw new ServiceImporterException( "Could not import service " + identity, e ); + } + } + + @SuppressWarnings( "raw" ) + public Object newProxy( InvocationHandler serviceInvocationHandler ) + { + if( type.isInterface() ) + { + return Proxy.newProxyInstance( type.getClassLoader(), + new Class[]{ type }, + serviceInvocationHandler ); + } + else + { + Class[] interfaces = type.getInterfaces(); + return Proxy.newProxyInstance( type.getClassLoader(), + interfaces, + serviceInvocationHandler ); + } + } + + @Override + public String toString() + { + return type.getName() + ":" + identity; + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServiceReferenceInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServiceReferenceInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServiceReferenceInstance.java new file mode 100644 index 0000000..750985f --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServiceReferenceInstance.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2008-2011, Rickard Ãberg. All Rights Reserved. + * Copyright (c) 2008-2013, Niclas Hedhman. All Rights Reserved. + * Copyright (c) 2012-2014, Paul Merlin. All Rights Reserved. + * + * Licensed 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.zest.runtime.service; + +import org.apache.zest.api.activation.Activation; +import org.apache.zest.api.activation.ActivationEventListener; +import org.apache.zest.api.activation.ActivationException; +import org.apache.zest.api.activation.PassivationException; +import org.apache.zest.api.service.ServiceImporterException; +import org.apache.zest.api.service.ServiceReference; +import org.apache.zest.api.service.ServiceUnavailableException; +import org.apache.zest.api.structure.Module; +import org.apache.zest.runtime.activation.ActivationDelegate; + +/** + * Implementation of ServiceReference. This manages the reference to the imported service. + * <p> + * Whenever the service is requested it is returned directly to the client. That means that + * to handle service passivation and unavailability correctly, any proxying must be done in the + * service importer. + * </p> + * @param <T> Service Type + */ +public final class ImportedServiceReferenceInstance<T> + implements ServiceReference<T>, Activation +{ + private volatile ImportedServiceInstance<T> serviceInstance; + private T instance; + private final Module module; + private final ImportedServiceModel serviceModel; + private final ActivationDelegate activation = new ActivationDelegate( this ); + private boolean active = false; + + public ImportedServiceReferenceInstance( ImportedServiceModel serviceModel, Module module ) + { + this.module = module; + this.serviceModel = serviceModel; + } + + @Override + public String identity() + { + return serviceModel.identity(); + } + + @Override + public Iterable<Class<?>> types() + { + return serviceModel.types(); + } + + @Override + public <T> T metaInfo( Class<T> infoType ) + { + return serviceModel.metaInfo( infoType ); + } + + @Override + public synchronized T get() + { + return getInstance(); + } + + public ImportedServiceModel serviceDescriptor() + { + return serviceModel; + } + + @Override + public void activate() + throws ActivationException + { + if( serviceModel.isImportOnStartup() ) + { + getInstance(); + } + } + + @Override + public void passivate() + throws PassivationException + { + if( serviceInstance != null ) + { + try + { + activation.passivate( new Runnable() + { + @Override + public void run() + { + active = false; + } + } ); + } + finally + { + serviceInstance = null; + active = false; + } + } + } + + @Override + public boolean isActive() + { + return active; + } + + @Override + public boolean isAvailable() + { + try + { + getInstance(); + return serviceInstance.isAvailable(); + } + catch( ServiceImporterException ex ) + { + return false; + } + } + + public Module module() + { + return module; + } + + private T getInstance() + throws ServiceImporterException + { + // DCL that works with Java 1.5 volatile semantics + if( serviceInstance == null ) + { + synchronized( this ) + { + if( serviceInstance == null ) + { + serviceInstance = serviceModel.<T>importInstance( module ); + instance = serviceInstance.instance(); + + try + { + activation.activate( serviceModel.newActivatorsInstance( module ), serviceInstance, new Runnable() + { + @Override + public void run() + { + active = true; + } + } ); + } + catch( Exception e ) + { + serviceInstance = null; + throw new ServiceUnavailableException( "Could not activate service " + serviceModel.identity(), e ); + } + } + } + } + + return instance; + } + + @Override + public String toString() + { + return serviceModel.identity() + ", active=" + isActive() + ", module='" + serviceModel.moduleName() + "'"; + } + + @Override + public void registerActivationEventListener( ActivationEventListener listener ) + { + activation.registerActivationEventListener( listener ); + } + + @Override + public void deregisterActivationEventListener( ActivationEventListener listener ) + { + activation.deregisterActivationEventListener( listener ); + } + + @Override + public int hashCode() + { + return identity().hashCode(); + } + + @Override + public boolean equals( Object obj ) + { + if( obj == null ) + { + return false; + } + if( getClass() != obj.getClass() ) + { + return false; + } + final ServiceReference other = (ServiceReference) obj; + return identity().equals( other.identity() ); + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServicesInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServicesInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServicesInstance.java new file mode 100644 index 0000000..f957f11 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServicesInstance.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2008, Rickard Ãberg. All Rights Reserved. + * Copyright (c) 2012, Paul Merlin. + * + * Licensed 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.zest.runtime.service; + +import java.util.List; +import org.apache.zest.api.activation.Activation; +import org.apache.zest.api.activation.ActivationEventListener; +import org.apache.zest.api.activation.ActivationEventListenerRegistration; +import org.apache.zest.api.activation.ActivationException; +import org.apache.zest.api.activation.PassivationException; +import org.apache.zest.api.common.Visibility; +import org.apache.zest.api.service.ServiceReference; +import org.apache.zest.functional.Iterables; +import org.apache.zest.functional.Specification; +import org.apache.zest.runtime.activation.ActivationDelegate; +import org.apache.zest.runtime.activation.ActivatorsInstance; + +import static org.apache.zest.api.util.Classes.instanceOf; +import static org.apache.zest.functional.Iterables.filter; + +/** + * JAVADOC + */ +public class ImportedServicesInstance + implements Activation, ActivationEventListenerRegistration +{ + private final ImportedServicesModel servicesModel; + private final List<ServiceReference> serviceReferences; + private final ActivationDelegate activation = new ActivationDelegate( this, false ); + + public ImportedServicesInstance( ImportedServicesModel servicesModel, + List<ServiceReference> serviceReferences + ) + { + this.servicesModel = servicesModel; + this.serviceReferences = serviceReferences; + for( ServiceReference serviceReference : serviceReferences ) + { + serviceReference.registerActivationEventListener( activation ); + } + } + + @Override + public void activate() + throws ActivationException + { + Iterable<Activation> activatees = Iterables.<Activation>cast( filter( instanceOf( Activation.class ), serviceReferences ) ); + activation.activate( ActivatorsInstance.EMPTY, activatees ); + } + + @Override + public void passivate() + throws PassivationException + { + activation.passivate(); + } + + public Iterable<ServiceReference> visibleServices( final Visibility visibility ) + { + return Iterables.filter( new Specification<ServiceReference>() + { + @Override + public boolean satisfiedBy( ServiceReference item ) + { + return ( (ImportedServiceReferenceInstance) item ).serviceDescriptor() + .visibility() + .ordinal() >= visibility.ordinal(); + } + }, serviceReferences ); + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder( "Services{" ); + String sep = " "; + for( ServiceReference serviceReference : serviceReferences ) + { + sb.append( sep ). + append( serviceReference.identity() ). + append( "(active=" ).append( serviceReference.isActive() ).append( ")" ); + sep = ", "; + } + return sb.append( " }" ).toString(); + } + + @Override + public void registerActivationEventListener( ActivationEventListener listener ) + { + activation.registerActivationEventListener( listener ); + } + + @Override + public void deregisterActivationEventListener( ActivationEventListener listener ) + { + activation.deregisterActivationEventListener( listener ); + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServicesModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServicesModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServicesModel.java new file mode 100644 index 0000000..5d19cc9 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/service/ImportedServicesModel.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2008, Rickard Ãberg. All Rights Reserved. + * + * Licensed 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.zest.runtime.service; + +import java.util.ArrayList; +import java.util.List; +import org.apache.zest.api.service.ServiceReference; +import org.apache.zest.functional.HierarchicalVisitor; +import org.apache.zest.functional.VisitableHierarchy; +import org.apache.zest.runtime.structure.ModuleInstance; + +/** + * JAVADOC + */ +public class ImportedServicesModel + implements VisitableHierarchy<Object, Object> +{ + private List<ImportedServiceModel> importedServiceModels; + + public ImportedServicesModel( List<ImportedServiceModel> importedServiceModels ) + { + this.importedServiceModels = importedServiceModels; + } + + public ImportedServicesInstance newInstance( ModuleInstance module ) + { + List<ServiceReference> serviceReferences = new ArrayList<ServiceReference>(); + for( ImportedServiceModel serviceModel : importedServiceModels ) + { + ImportedServiceReferenceInstance serviceReferenceInstance = new ImportedServiceReferenceInstance( serviceModel, module ); + serviceReferences.add( serviceReferenceInstance ); + } + + return new ImportedServicesInstance( this, serviceReferences ); + } + + @Override + public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor ) + throws ThrowableType + { + if( visitor.visitEnter( this ) ) + { + for( ImportedServiceModel importedServiceModel : importedServiceModels ) + { + if( !importedServiceModel.accept( visitor ) ) + { + break; + } + } + } + return visitor.visitLeave( this ); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/service/ServiceInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/service/ServiceInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/service/ServiceInstance.java new file mode 100644 index 0000000..727b6fd --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/service/ServiceInstance.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2009, Rickard Ãberg. All Rights Reserved. + * + * Licensed 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.zest.runtime.service; + +import java.lang.reflect.Proxy; +import org.apache.zest.api.activation.Activation; +import org.apache.zest.api.activation.ActivationException; +import org.apache.zest.api.activation.PassivationException; +import org.apache.zest.api.configuration.Configuration; +import org.apache.zest.api.configuration.Enabled; +import org.apache.zest.api.service.Availability; +import org.apache.zest.api.service.ServiceComposite; +import org.apache.zest.api.util.Classes; +import org.apache.zest.runtime.composite.TransientInstance; +import org.apache.zest.runtime.composite.TransientStateInstance; +import org.apache.zest.runtime.structure.ModuleInstance; + +/** + * JAVADOC + */ +public class ServiceInstance + extends TransientInstance + implements Activation +{ + public static TransientInstance serviceInstanceOf( ServiceComposite composite ) + { + return (TransientInstance) Proxy.getInvocationHandler( composite ); + } + + private final boolean implementsServiceAvailable; + private final boolean hasEnabledConfiguration; + + public ServiceInstance( ServiceModel compositeModel, + ModuleInstance moduleInstance, + Object[] mixins, + TransientStateInstance state + ) + { + super( compositeModel, moduleInstance, mixins, state ); + + implementsServiceAvailable = + Classes.assignableTypeSpecification( Availability.class ).satisfiedBy( descriptor() ); + hasEnabledConfiguration = compositeModel.configurationType() != null + && Enabled.class.isAssignableFrom( compositeModel.configurationType() ); + } + + @Override + public void activate() + throws ActivationException + { + // NOOP + } + + @Override + public void passivate() + throws PassivationException + { + // NOOP + } + + @SuppressWarnings( "unchecked" ) + public boolean isAvailable() + { + // Check Enabled in configuration first + if( hasEnabledConfiguration && !( (Configuration<Enabled>) proxy() ).get().enabled().get() ) + { + return false; + } + + // Ask service if it's available + return !implementsServiceAvailable || ( (Availability) proxy() ).isAvailable(); + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/service/ServiceModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/service/ServiceModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/service/ServiceModel.java new file mode 100644 index 0000000..86eaa3f --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/service/ServiceModel.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2008-2011, Rickard Ãberg. All Rights Reserved. + * Copyright (c) 2008-2013, Niclas Hedhman. All Rights Reserved. + * Copyright (c) 2012-2014, Paul Merlin. All Rights Reserved. + * + * Licensed 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.zest.runtime.service; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.util.HashMap; +import java.util.Map; +import org.apache.zest.api.common.MetaInfo; +import org.apache.zest.api.common.Visibility; +import org.apache.zest.api.configuration.Configuration; +import org.apache.zest.api.entity.Identity; +import org.apache.zest.api.injection.scope.This; +import org.apache.zest.api.property.Property; +import org.apache.zest.api.service.ServiceDescriptor; +import org.apache.zest.api.structure.Module; +import org.apache.zest.api.util.Classes; +import org.apache.zest.functional.HierarchicalVisitor; +import org.apache.zest.functional.Specifications; +import org.apache.zest.runtime.activation.ActivatorsInstance; +import org.apache.zest.runtime.activation.ActivatorsModel; +import org.apache.zest.runtime.composite.CompositeMethodsModel; +import org.apache.zest.runtime.composite.CompositeModel; +import org.apache.zest.runtime.composite.MixinModel; +import org.apache.zest.runtime.composite.MixinsModel; +import org.apache.zest.runtime.composite.StateModel; +import org.apache.zest.runtime.composite.TransientStateInstance; +import org.apache.zest.runtime.composite.UsesInstance; +import org.apache.zest.runtime.injection.DependencyModel; +import org.apache.zest.runtime.injection.InjectionContext; +import org.apache.zest.runtime.property.PropertyInstance; +import org.apache.zest.runtime.property.PropertyModel; +import org.apache.zest.runtime.structure.ModuleInstance; + +import static org.apache.zest.functional.Iterables.filter; +import static org.apache.zest.functional.Specifications.and; +import static org.apache.zest.functional.Specifications.translate; + +/** + * JAVADOC + */ +public final class ServiceModel extends CompositeModel + implements ServiceDescriptor +{ + private static Method identityMethod; + + static + { + try + { + identityMethod = Identity.class.getMethod( "identity" ); + } + catch( NoSuchMethodException e ) + { + e.printStackTrace(); + } + } + + private final String identity; + private final boolean instantiateOnStartup; + private final ActivatorsModel<?> activatorsModel; + @SuppressWarnings( "raw" ) + private final Class configurationType; + + public ServiceModel( Iterable<Class<?>> types, + Visibility visibility, + MetaInfo metaInfo, + ActivatorsModel<?> activatorsModel, + MixinsModel mixinsModel, + StateModel stateModel, + CompositeMethodsModel compositeMethodsModel, + String identity, + boolean instantiateOnStartup + ) + { + super( types, visibility, metaInfo, mixinsModel, stateModel, compositeMethodsModel ); + + this.identity = identity; + this.instantiateOnStartup = instantiateOnStartup; + this.activatorsModel = activatorsModel; + + // Calculate configuration type + this.configurationType = calculateConfigurationType(); + } + + @Override + public boolean isInstantiateOnStartup() + { + return instantiateOnStartup; + } + + @Override + public String identity() + { + return identity; + } + + @SuppressWarnings( {"raw", "unchecked"} ) + public ActivatorsInstance<?> newActivatorsInstance( Module module ) throws Exception + { + return new ActivatorsInstance( activatorsModel.newInstances( module ) ); + } + + @Override + @SuppressWarnings( "unchecked" ) + public <T> Class<T> configurationType() + { + return configurationType; + } + + @Override + public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor ) + throws ThrowableType + { + if( visitor.visitEnter( this ) ) + { + if( activatorsModel.accept( visitor ) ) + { + if( compositeMethodsModel.accept( visitor ) ) + { + if( stateModel.accept( visitor ) ) + { + mixinsModel.accept( visitor ); + } + } + } + } + return visitor.visitLeave( this ); + } + + public ServiceInstance newInstance( final ModuleInstance module ) + { + Object[] mixins = mixinsModel.newMixinHolder(); + + Map<AccessibleObject, Property<?>> properties = new HashMap<>(); + for( PropertyModel propertyModel : stateModel.properties() ) + { + Object initialValue = propertyModel.initialValue( module ); + if( propertyModel.accessor().equals( identityMethod ) ) + { + initialValue = identity; + } + + Property<?> property = new PropertyInstance<>( propertyModel, initialValue ); + properties.put( propertyModel.accessor(), property ); + } + + TransientStateInstance state = new TransientStateInstance( properties ); + ServiceInstance compositeInstance = new ServiceInstance( this, module, mixins, state ); + + // Instantiate all mixins + int i = 0; + UsesInstance uses = UsesInstance.EMPTY_USES.use( this ); + InjectionContext injectionContext = new InjectionContext( compositeInstance, uses, state ); + for( MixinModel mixinModel : mixinsModel.mixinModels() ) + { + mixins[ i++ ] = mixinModel.newInstance( injectionContext ); + } + + return compositeInstance; + } + + @Override + public String toString() + { + return super.toString() + ":" + identity; + } + + @SuppressWarnings( { "raw", "unchecked" } ) + public Class calculateConfigurationType() + { + Class injectionClass = null; + Iterable<DependencyModel> configurationThisDependencies = filter( and( translate( new DependencyModel.InjectionTypeFunction(), Specifications + .<Class<?>>in( Configuration.class ) ), new DependencyModel.ScopeSpecification( This.class ) ), dependencies() ); + for( DependencyModel dependencyModel : configurationThisDependencies ) + { + if( dependencyModel.rawInjectionType() + .equals( Configuration.class ) && dependencyModel.injectionType() instanceof ParameterizedType ) + { + Class<?> type = Classes.RAW_CLASS + .map( ( (ParameterizedType) dependencyModel.injectionType() ).getActualTypeArguments()[ 0 ] ); + if( injectionClass == null ) + { + injectionClass = type; + } + else + { + if( injectionClass.isAssignableFrom( type ) ) + { + injectionClass = type; + } + } + } + } + return injectionClass; + } + +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/service/ServiceReferenceInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/service/ServiceReferenceInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/service/ServiceReferenceInstance.java new file mode 100644 index 0000000..6543917 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/service/ServiceReferenceInstance.java @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2008-2011, Rickard Ãberg. All Rights Reserved. + * Copyright (c) 2008-2013, Niclas Hedhman. All Rights Reserved. + * Copyright (c) 2012-2014, Paul Merlin. All Rights Reserved. + * + * Licensed 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.zest.runtime.service; + +import java.lang.reflect.Method; +import org.apache.zest.api.activation.Activation; +import org.apache.zest.api.activation.ActivationEventListener; +import org.apache.zest.api.activation.ActivationException; +import org.apache.zest.api.activation.PassivationException; +import org.apache.zest.api.composite.CompositeDescriptor; +import org.apache.zest.api.composite.CompositeInstance; +import org.apache.zest.api.property.StateHolder; +import org.apache.zest.api.service.ServiceDescriptor; +import org.apache.zest.api.service.ServiceImporterException; +import org.apache.zest.api.service.ServiceReference; +import org.apache.zest.api.service.ServiceUnavailableException; +import org.apache.zest.api.structure.Module; +import org.apache.zest.runtime.activation.ActivationDelegate; +import org.apache.zest.runtime.structure.ModuleInstance; + +/** + * Implementation of ServiceReference. + * <p> + * This manages the actual instance of the service and implements the service Activation. + * </p> + * <p> + * Whenever the service is requested a proxy is returned which points to this class. This means + * that the instance can be passivated even though a client is holding on to a service proxy. + * </p> + * @param <T> Service Type + */ +public final class ServiceReferenceInstance<T> + implements ServiceReference<T>, Activation +{ + private volatile ServiceInstance instance; + private final T serviceProxy; + private final ModuleInstance module; + private final ServiceModel serviceModel; + private final ActivationDelegate activation = new ActivationDelegate( this ); + private boolean active = false; + + public ServiceReferenceInstance( ServiceModel serviceModel, ModuleInstance module ) + { + this.module = module; + this.serviceModel = serviceModel; + + serviceProxy = newProxy(); + } + + @Override + public String identity() + { + return serviceModel.identity(); + } + + @Override + public Iterable<Class<?>> types() + { + return serviceModel.types(); + } + + @Override + public <T> T metaInfo( Class<T> infoType ) + { + return serviceModel.metaInfo( infoType ); + } + + @Override + public synchronized T get() + { + return serviceProxy; + } + + @Override + public boolean isActive() + { + return active; + } + + @Override + public boolean isAvailable() + { + return getInstance().isAvailable(); + } + + public Module module() + { + return module; + } + + @Override + public void activate() + throws ActivationException + { + if( serviceModel.isInstantiateOnStartup() ) + { + getInstance(); + } + } + + @Override + public void passivate() + throws PassivationException + { + if( instance != null ) + { + try { + activation.passivate( new Runnable() + { + @Override + public void run() + { + active = false; + } + } ); + } finally { + instance = null; + active = false; + } + } + } + + private ServiceInstance getInstance() + throws ServiceImporterException + { + // DCL that works with Java 1.5 volatile semantics + if( instance == null ) + { + synchronized( this ) + { + if( instance == null ) + { + instance = serviceModel.newInstance( module ); + + try + { + activation.activate( serviceModel.newActivatorsInstance( module ), instance, new Runnable() + { + @Override + public void run() + { + active = true; + } + } ); + } + catch( Exception e ) + { + instance = null; + throw new ServiceUnavailableException( "Could not activate service " + serviceModel.identity(), e ); + } + } + } + } + + return instance; + } + + @Override + public String toString() + { + return serviceModel.identity() + "(active=" + isActive() + ",module='" + module.name() + "')"; + } + + @SuppressWarnings( "unchecked" ) + public T newProxy() + { + return (T) serviceModel.newProxy( new ServiceReferenceInstance.ServiceInvocationHandler() ); + } + + public ServiceDescriptor serviceDescriptor() + { + return serviceModel; + } + + public final class ServiceInvocationHandler + implements CompositeInstance + { + @Override + @SuppressWarnings( "unchecked" ) + public <T> T proxy() + { + return (T) ServiceReferenceInstance.this.get(); + } + + @Override + public <T> T newProxy( Class<T> mixinType ) + throws IllegalArgumentException + { + return getInstance().newProxy( mixinType ); + } + + @Override + public <T> T metaInfo( Class<T> infoType ) + { + return ServiceReferenceInstance.this.metaInfo( infoType ); + } + + @Override + public Iterable<Class<?>> types() + { + return ServiceReferenceInstance.this.types(); + } + + @Override + public CompositeDescriptor descriptor() + { + return ServiceReferenceInstance.this.serviceDescriptor(); + } + + @Override + public Object invokeComposite( Method method, Object[] args ) + throws Throwable + { + return getInstance().invokeComposite( method, args ); + } + + @Override + public StateHolder state() + { + return getInstance().state(); + } + + @Override + public Object invoke( Object object, Method method, Object[] objects ) + throws Throwable + { + if( method.getDeclaringClass().equals( Object.class ) ) + { + switch( method.getName() ) + { + case "toString": + return serviceModel.toString(); + case "equals": + return objects[0] == object; + case "hashCode": + return serviceModel.toString().hashCode(); + } + } + + ServiceInstance instance = getInstance(); + +/* + if (!instance.isAvailable()) + { + throw new ServiceUnavailableException("Service is currently not available"); + } + +*/ + return instance.invoke( object, method, objects ); + } + + @Override + public String toString() + { + return serviceModel.toString(); + } + + @Override + public Module module() + { + return module; + } + } + + @Override + public void registerActivationEventListener( ActivationEventListener listener ) + { + activation.registerActivationEventListener( listener ); + } + + @Override + public void deregisterActivationEventListener( ActivationEventListener listener ) + { + activation.deregisterActivationEventListener( listener ); + } + + @Override + public int hashCode() + { + return identity().hashCode(); + } + + @Override + @SuppressWarnings( "raw" ) + public boolean equals( Object obj ) + { + if ( obj == null ) { + return false; + } + if ( getClass() != obj.getClass() ) { + return false; + } + final ServiceReference other = ( ServiceReference ) obj; + return identity().equals( other.identity() ); + } + +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/service/ServicesInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/service/ServicesInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/service/ServicesInstance.java new file mode 100644 index 0000000..bb03428 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/service/ServicesInstance.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2008, Rickard Ãberg. All Rights Reserved. + * Copyright (c) 2012, Paul Merlin. + * + * Licensed 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.zest.runtime.service; + +import java.util.List; +import org.apache.zest.api.activation.Activation; +import org.apache.zest.api.activation.ActivationEventListener; +import org.apache.zest.api.activation.ActivationEventListenerRegistration; +import org.apache.zest.api.activation.ActivationException; +import org.apache.zest.api.activation.PassivationException; +import org.apache.zest.api.common.Visibility; +import org.apache.zest.api.service.ServiceReference; +import org.apache.zest.functional.Iterables; +import org.apache.zest.functional.Specification; +import org.apache.zest.runtime.activation.ActivationDelegate; +import org.apache.zest.runtime.activation.ActivatorsInstance; + +import static org.apache.zest.api.util.Classes.instanceOf; +import static org.apache.zest.functional.Iterables.filter; + +/** + * JAVADOC + */ +public class ServicesInstance + implements Activation, ActivationEventListenerRegistration +{ + private final ServicesModel servicesModel; + private final List<ServiceReference> serviceReferences; + private final ActivationDelegate activation = new ActivationDelegate( this, false ); + + public ServicesInstance( ServicesModel servicesModel, List<ServiceReference> serviceReferences ) + { + this.servicesModel = servicesModel; + this.serviceReferences = serviceReferences; + for( ServiceReference serviceReference : serviceReferences ) + { + serviceReference.registerActivationEventListener( activation ); + } + } + + @Override + public void activate() + throws ActivationException + { + Iterable<Activation> activatees = Iterables.<Activation>cast( filter( instanceOf( Activation.class ), serviceReferences ) ); + activation.activate( ActivatorsInstance.EMPTY, activatees ); + } + + @Override + public void passivate() + throws PassivationException + { + activation.passivate(); + } + + public Iterable<ServiceReference> visibleServices( final Visibility visibility ) + { + return Iterables.filter( new Specification<ServiceReference>() + { + @Override + public boolean satisfiedBy( ServiceReference item ) + { + return ( (ServiceReferenceInstance) item ).serviceDescriptor() + .visibility() + .ordinal() >= visibility.ordinal(); + } + }, serviceReferences ); + } + + @Override + public String toString() + { + StringBuilder sb = new StringBuilder( "Services{" ); + String sep = " "; + for( ServiceReference serviceReference : serviceReferences ) + { + sb.append( sep ). + append( serviceReference.identity() ). + append( "(active=" ).append( serviceReference.isActive() ).append( ")" ); + sep = ", "; + } + return sb.append( " }" ).toString(); + } + + @Override + public void registerActivationEventListener( ActivationEventListener listener ) + { + activation.registerActivationEventListener( listener ); + } + + @Override + public void deregisterActivationEventListener( ActivationEventListener listener ) + { + activation.deregisterActivationEventListener( listener ); + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/service/ServicesModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/service/ServicesModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/service/ServicesModel.java new file mode 100644 index 0000000..ee8b46e --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/service/ServicesModel.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2008, Rickard Ãberg. All Rights Reserved. + * + * Licensed 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.zest.runtime.service; + +import java.util.ArrayList; +import java.util.List; +import org.apache.zest.api.service.ServiceReference; +import org.apache.zest.functional.HierarchicalVisitor; +import org.apache.zest.functional.VisitableHierarchy; +import org.apache.zest.runtime.structure.ModuleInstance; + +/** + * JAVADOC + */ +public class ServicesModel + implements VisitableHierarchy<Object, Object> +{ + private final Iterable<ServiceModel> serviceModels; + + public ServicesModel( Iterable<ServiceModel> serviceModels ) + { + this.serviceModels = serviceModels; + } + + public ServicesInstance newInstance( ModuleInstance module ) + { + List<ServiceReference> serviceReferences = new ArrayList<ServiceReference>(); + for( ServiceModel serviceModel : serviceModels ) + { + ServiceReferenceInstance serviceReferenceInstance = new ServiceReferenceInstance( serviceModel, module ); + serviceReferences.add( serviceReferenceInstance ); + } + + return new ServicesInstance( this, serviceReferences ); + } + + @Override + public <ThrowableType extends Throwable> boolean accept( HierarchicalVisitor<? super Object, ? super Object, ThrowableType> visitor ) + throws ThrowableType + { + if( visitor.visitEnter( this ) ) + { + for( ServiceModel serviceModel : serviceModels ) + { + if( !serviceModel.accept( visitor ) ) + { + break; + } + } + } + return visitor.visitLeave( this ); + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/structure/ApplicationInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/structure/ApplicationInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/structure/ApplicationInstance.java new file mode 100644 index 0000000..cd739e0 --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/structure/ApplicationInstance.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2008, Rickard Ãberg. All Rights Reserved. + * Copyright (c) 2008, Niclas Hedhman. + * + * Licensed 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.zest.runtime.structure; + +import java.util.ArrayList; +import java.util.List; +import org.apache.zest.api.activation.ActivationEventListener; +import org.apache.zest.api.activation.ActivationException; +import org.apache.zest.api.activation.PassivationException; +import org.apache.zest.api.common.MetaInfo; +import org.apache.zest.api.structure.Application; +import org.apache.zest.api.structure.ApplicationDescriptor; +import org.apache.zest.api.structure.Layer; +import org.apache.zest.api.structure.Module; +import org.apache.zest.bootstrap.Qi4jRuntime; +import org.apache.zest.runtime.activation.ActivationDelegate; + +/** + * Instance of a Zest 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 Qi4jRuntime runtime; + private final MetaInfo instanceMetaInfo; + // Eager instance objects + private final ActivationDelegate activation; + private final List<LayerInstance> layerInstances; + + public ApplicationInstance( ApplicationModel model, Qi4jRuntime 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 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 + /* package */ void addLayer( LayerInstance layer ) + { + layer.registerActivationEventListener( activation ); + layerInstances.add( layer ); + } + + public Qi4jRuntime runtime() + { + return runtime; + } + +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/061ddaa0/core/runtime/src/main/java/org/apache/zest/runtime/structure/ApplicationModel.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/structure/ApplicationModel.java b/core/runtime/src/main/java/org/apache/zest/runtime/structure/ApplicationModel.java new file mode 100644 index 0000000..a5e9d5b --- /dev/null +++ b/core/runtime/src/main/java/org/apache/zest/runtime/structure/ApplicationModel.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2008-2011, Rickard Ãberg. All Rights Reserved. + * Copyright (c) 2008-2013, Niclas Hedhman. All Rights Reserved. + * Copyright (c) 2012-2014, Paul Merlin. All Rights Reserved. + * + * Licensed 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.zest.runtime.structure; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.zest.api.Qi4j; +import org.apache.zest.api.activation.ActivationException; +import org.apache.zest.api.common.InvalidApplicationException; +import org.apache.zest.api.common.MetaInfo; +import org.apache.zest.api.structure.Application; +import org.apache.zest.api.structure.ApplicationDescriptor; +import org.apache.zest.bootstrap.Qi4jRuntime; +import org.apache.zest.functional.HierarchicalVisitor; +import org.apache.zest.runtime.activation.ActivatorsInstance; +import org.apache.zest.runtime.activation.ActivatorsModel; +import org.apache.zest.runtime.injection.InjectionProviderFactory; +import org.apache.zest.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( Qi4j runtime, Object... importedServiceInstances ) + throws InvalidApplicationException + { + MetaInfo instanceMetaInfo = new MetaInfo( metaInfo ); + for( Object importedServiceInstance : importedServiceInstances ) + { + instanceMetaInfo.set( importedServiceInstance ); + } + + ApplicationInstance applicationInstance = new ApplicationInstance( this, (Qi4jRuntime) runtime, instanceMetaInfo ); + + // Create layer instances + Map<LayerModel, LayerInstance> layerInstanceMap = new HashMap<>(); + Map<LayerModel, List<LayerInstance>> usedLayers = new HashMap<>(); + for( LayerModel layer : layers ) + { + List<LayerInstance> usedLayerInstances = new ArrayList<>(); + usedLayers.put( layer, usedLayerInstances ); + UsedLayersInstance usedLayersInstance = layer.usedLayers().newInstance( usedLayerInstances ); + LayerInstance layerInstance = layer.newInstance( applicationInstance, usedLayersInstance ); + applicationInstance.addLayer( layerInstance ); + layerInstanceMap.put( layer, layerInstance ); + } + + // Resolve used layer instances + for( LayerModel layer : layers ) + { + List<LayerInstance> usedLayerInstances = usedLayers.get( layer ); + for( LayerModel usedLayer : layer.usedLayers().layers() ) + { + LayerInstance layerInstance = layerInstanceMap.get( usedLayer ); + if( layerInstance == null ) + { + throw new InvalidApplicationException( "Could not find used layer:" + usedLayer.name() ); + } + usedLayerInstances.add( layerInstance ); + } + } + + return applicationInstance; + } + + public InjectionProviderFactory injectionProviderFactory() + { + return ipf; + } + + @Override + public String toString() + { + final StringBuilder sb = new StringBuilder(); + sb.append( "ApplicationModel" ); + sb.append( "{name='" ).append( name ).append( '\'' ); + sb.append( ", version='" ).append( version ).append( '\'' ); + sb.append( ", mode=" ).append( mode ); + sb.append( '}' ); + return sb.toString(); + } +}
