http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/util/Classes.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/util/Classes.java b/core/api/src/main/java/org/apache/zest/api/util/Classes.java new file mode 100644 index 0000000..79f1d32 --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/util/Classes.java @@ -0,0 +1,699 @@ +/* + * 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.api.util; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.apache.zest.api.composite.ModelDescriptor; +import org.apache.zest.functional.Function; +import org.apache.zest.functional.Iterables; +import org.apache.zest.functional.Specification; + +import static org.apache.zest.functional.Iterables.cast; +import static org.apache.zest.functional.Iterables.empty; +import static org.apache.zest.functional.Iterables.flatten; +import static org.apache.zest.functional.Iterables.flattenIterables; +import static org.apache.zest.functional.Iterables.iterable; +import static org.apache.zest.functional.Iterables.map; +import static org.apache.zest.functional.Iterables.matchesAny; +import static org.apache.zest.functional.Iterables.prepend; + +/** + * Useful methods for handling Classes. + */ +public final class Classes +{ + private final static Map<Type, Type> wrapperClasses = new HashMap<>(); + + static + { + wrapperClasses.put( boolean.class, Boolean.class ); + wrapperClasses.put( byte.class, Byte.class ); + wrapperClasses.put( short.class, Short.class ); + wrapperClasses.put( char.class, Character.class ); + wrapperClasses.put( int.class, Integer.class ); + wrapperClasses.put( long.class, Long.class ); + wrapperClasses.put( float.class, Float.class ); + wrapperClasses.put( double.class, Double.class ); + } + + private final static Map<Type, Type> primitiveClasses = new HashMap<>(); + + static + { + primitiveClasses.put( boolean.class, Boolean.class ); + primitiveClasses.put( byte.class, Byte.class ); + primitiveClasses.put( short.class, Short.class ); + primitiveClasses.put( char.class, Character.class ); + primitiveClasses.put( int.class, Integer.class ); + primitiveClasses.put( long.class, Long.class ); + primitiveClasses.put( float.class, Float.class ); + primitiveClasses.put( double.class, Double.class ); + } + + /** + * Convert from primitive class (int, short, double, etc.) to wrapper class (Integer, Short, Double, etc.). + * Return the same class if it's not a primitive class. This can therefore safely be used on all types + * to ensure that they are not primitives. + */ + private static final Function<Type, Type> WRAPPER_CLASS = new Function<Type, Type>() + { + @Override + public Type map( Type aClass ) + { + Type wrapperClass = wrapperClasses.get( aClass ); + return wrapperClass == null ? aClass : wrapperClass; + } + }; + + /** + * Convert from wrapper class (Integer, Short, Double, etc.) to primitive class (int, short, double, etc.). + * Return the same class if it's not a wrapper class. This can therefore safely be used on all types + * to ensure that they are primitives if possible. + */ + @SuppressWarnings( "UnusedDeclaration" ) + private static final Function<Type, Type> PRIMITIVE_CLASS = new Function<Type, Type>() + { + @Override + public Type map( Type aClass ) + { + Type primitiveClass = primitiveClasses.get( aClass ); + return primitiveClass == null ? aClass : primitiveClass; + } + }; + + /** + * Function that extract the raw class of a type. + */ + public static final Function<Type, Class<?>> RAW_CLASS = new Function<Type, Class<?>>() + { + @Override + public Class<?> map( Type genericType ) + { + // Calculate raw type + if( genericType instanceof Class ) + { + return (Class<?>) genericType; + } + else if( genericType instanceof ParameterizedType ) + { + return (Class<?>) ( (ParameterizedType) genericType ).getRawType(); + } + else if( genericType instanceof TypeVariable ) + { + return (Class<?>) ( (TypeVariable) genericType ).getGenericDeclaration(); + } + else if( genericType instanceof WildcardType ) + { + return (Class<?>) ( (WildcardType) genericType ).getUpperBounds()[ 0]; + } + else if( genericType instanceof GenericArrayType ) + { + Object temp = Array.newInstance( (Class<?>) ( (GenericArrayType) genericType ).getGenericComponentType(), 0 ); + return temp.getClass(); + } + throw new IllegalArgumentException( "Could not extract the raw class of " + genericType ); + } + }; + + private static final Function<AccessibleObject, Type> TYPE_OF = new Function<AccessibleObject, Type>() + { + @Override + public Type map( AccessibleObject accessor ) + { + return accessor instanceof Method ? ( (Method) accessor ).getGenericReturnType() : ( (Field) accessor ).getGenericType(); + } + }; + + private static final Function<Type, Iterable<Class<?>>> CLASS_HIERARCHY = new Function<Type, Iterable<Class<?>>>() + { + @Override + @SuppressWarnings( {"raw", "unchecked"} ) + public Iterable<Class<?>> map( Type type ) + { + if( type == null ) + { + return empty(); + } + if( type.equals( Object.class ) ) + { + Class<?> aClass = (Class<?>) type; + return cast( iterable( aClass ) ); + } + else + { + type = RAW_CLASS.map( type ); + Class superclass = ( (Class) type ).getSuperclass(); + return prepend( (Class<?>) type, map( superclass ) ); + } + } + }; + + @SuppressWarnings( "raw" ) + private static final Function<Type, Iterable<Type>> INTERFACES_OF = new Function<Type, Iterable<Type>>() + { + @Override + public Iterable<Type> map( Type type ) + { + Class clazz = RAW_CLASS.map( type ); + + if( clazz.isInterface() ) + { + Iterable<Type> genericInterfaces = iterable( clazz.getGenericInterfaces() ); + Iterable<Type> flattenIterables = flattenIterables( Iterables.map( INTERFACES_OF, genericInterfaces ) ); + return prepend( type, flattenIterables ); + } + else + { + if( type.equals( Object.class ) ) + { + return iterable( clazz.getGenericInterfaces() ); + } + else + { + return flatten( flattenIterables( Iterables.map( INTERFACES_OF, + iterable( clazz.getGenericInterfaces() ) ) ), + INTERFACES_OF.map( RAW_CLASS.map( type ).getSuperclass() ) ); + } + } + } + }; + + @SuppressWarnings( "raw" ) + private static final Function<Type, Iterable<Type>> TYPES_OF = new Function<Type, Iterable<Type>>() + { + @Override + public Iterable<Type> map( Type type ) + { + Class clazz = RAW_CLASS.map( type ); + + if( clazz.isInterface() ) + { + Iterable<Type> genericInterfaces = iterable( clazz.getGenericInterfaces() ); + Iterable<Type> flattenIterables = flattenIterables( Iterables.map( INTERFACES_OF, genericInterfaces ) ); + return prepend( clazz, flattenIterables ); + } + else + { + return flatten( CLASS_HIERARCHY.map( type ), + flattenIterables( Iterables.map( INTERFACES_OF, CLASS_HIERARCHY.map( type ) ) ) ); + } + } + }; + + public static Type typeOf( AccessibleObject from ) + { + return TYPE_OF.map( from ); + } + + public static Iterable<Type> typesOf( Iterable<Type> types ) + { + Iterable<Type> result = empty(); + for( Type type : types ) + { + result = flatten( result, typesOf( type ) ); + } + return result; + } + + public static Iterable<Type> typesOf( Type type ) + { + return TYPES_OF.map( type ); + } + + public static Iterable<? extends Type> interfacesOf( Iterable<? extends Type> types ) + { + Iterable<Type> result = empty(); + for( Type type : types ) + { + result = flatten( result, interfacesOf( type ) ); + } + return result; + } + + public static Iterable<Type> interfacesOf( Type type ) + { + return INTERFACES_OF.map( type ); + } + + public static Iterable<Class<?>> classHierarchy( Class<?> type ) + { + return CLASS_HIERARCHY.map( type ); + } + + public static Type wrapperClass( Type type ) + { + return WRAPPER_CLASS.map( type ); + } + + public static Specification<Class<?>> isAssignableFrom( final Class clazz ) + { + return new Specification<Class<?>>() + { + @Override + @SuppressWarnings( "unchecked" ) + public boolean satisfiedBy( Class<?> item ) + { + return clazz.isAssignableFrom( item ); + } + }; + } + + @SuppressWarnings( "raw" ) + public static Specification<Object> instanceOf( final Class clazz ) + { + return new Specification<Object>() + { + @Override + public boolean satisfiedBy( Object item ) + { + return clazz.isInstance( item ); + } + }; + } + + public static Specification<Class<?>> hasModifier( final int classModifier ) + { + return new Specification<Class<?>>() + { + @Override + public boolean satisfiedBy( Class<?> item ) + { + return ( item.getModifiers() & classModifier ) != 0; + } + }; + } + + public static <T> Function<Type, Iterable<T>> forClassHierarchy( final Function<Class<?>, Iterable<T>> function ) + { + return new Function<Type, Iterable<T>>() + { + @Override + public Iterable<T> map( Type type ) + { + return flattenIterables( Iterables.map( function, CLASS_HIERARCHY.map( type ) ) ); + } + }; + } + + public static <T> Function<Type, Iterable<T>> forTypes( final Function<Type, Iterable<T>> function ) + { + return new Function<Type, Iterable<T>>() + { + @Override + public Iterable<T> map( Type type ) + { + return flattenIterables( Iterables.map( function, TYPES_OF.map( type ) ) ); + } + }; + } + + @SuppressWarnings( "raw" ) + public static Set<Class<?>> interfacesWithMethods( Set<Class<?>> interfaces ) + { + Set<Class<?>> newSet = new LinkedHashSet<>(); + for( Class type : interfaces ) + { + if( type.isInterface() && type.getDeclaredMethods().length > 0 ) + { + newSet.add( type ); + } + } + + return newSet; + } + + public static String simpleGenericNameOf( Type type ) + { + StringBuilder sb = new StringBuilder(); + simpleGenericNameOf( sb, type ); + return sb.toString(); + } + + @SuppressWarnings( "raw" ) + private static void simpleGenericNameOf( StringBuilder sb, Type type ) + { + if( type instanceof Class ) + { + sb.append( ( (Class) type ).getSimpleName() ); + } + else if( type instanceof ParameterizedType ) + { + ParameterizedType pt = (ParameterizedType) type; + simpleGenericNameOf( sb, pt.getRawType() ); + sb.append( "<" ); + boolean atLeastOne = false; + for( Type typeArgument : pt.getActualTypeArguments() ) + { + if( atLeastOne ) + { + sb.append( ", " ); + } + simpleGenericNameOf( sb, typeArgument ); + atLeastOne = true; + } + sb.append( ">" ); + } + else if( type instanceof GenericArrayType ) + { + GenericArrayType gat = (GenericArrayType) type; + simpleGenericNameOf( sb, gat.getGenericComponentType() ); + sb.append( "[]" ); + } + else if( type instanceof TypeVariable ) + { + TypeVariable tv = (TypeVariable) type; + sb.append( tv.getName() ); + } + else if( type instanceof WildcardType ) + { + WildcardType wt = (WildcardType) type; + sb.append( "? extends " ); + boolean atLeastOne = false; + for( Type typeArgument : wt.getUpperBounds() ) + { + if( atLeastOne ) + { + sb.append( ", " ); + } + simpleGenericNameOf( sb, typeArgument ); + atLeastOne = true; + } + } + else + { + throw new IllegalArgumentException( "Don't know how to deal with type:" + type ); + } + } + + @SuppressWarnings( "UnusedDeclaration" ) + public static <AnnotationType extends Annotation> + AnnotationType findAnnotationOfTypeOrAnyOfSuperTypes( Class<?> type, Class<AnnotationType> annotationClass ) + { + AnnotationType result = null; + for( Type clazz : Classes.TYPES_OF.map( type ) ) + { + result = Classes.RAW_CLASS.map( clazz ).getAnnotation( annotationClass ); + if( result != null ) + { + break; + } + } + + return result; + } + + public static Specification<Member> memberNamed( final String name ) + { + return new Specification<Member>() + { + @Override + public boolean satisfiedBy( Member item ) + { + return item.getName().equals( name ); + } + }; + } + + /** + * Given a type variable, find what it resolves to given the declaring class where type + * variable was found and a top class that extends the declaring class. + * + * @param name The TypeVariable name. + * @param declaringClass The class where the TypeVariable is declared. + * @param topClass The top class that extends the declaringClass + * + * @return The Type instance of the given TypeVariable + */ + @SuppressWarnings( "raw" ) + public static Type resolveTypeVariable( TypeVariable name, Class declaringClass, Class topClass ) + { + Type type = resolveTypeVariable( name, declaringClass, new HashMap<TypeVariable, Type>(), topClass ); + if( type == null ) + { + type = Object.class; + } + return type; + } + + @SuppressWarnings( "raw" ) + private static Type resolveTypeVariable( TypeVariable name, + Class declaringClass, + Map<TypeVariable, Type> mappings, + Class current + ) + { + if( current.equals( declaringClass ) ) + { + Type resolvedType = name; + while( resolvedType instanceof TypeVariable ) + { + resolvedType = mappings.get( resolvedType ); + } + return resolvedType; + } + + List<Type> types = new ArrayList<>(); + for( Type type : current.getGenericInterfaces() ) + { + Iterable<Type> interfaces = Classes.INTERFACES_OF.map( type ); + for( Type anInterface : interfaces ) + { + if( !types.contains( anInterface ) ) + { + types.add( anInterface ); + } + } + types.add( type ); + } + + if( current.getGenericSuperclass() != null ) + { + types.add( current.getGenericSuperclass() ); + } + + for( Type type : types ) + { + Class subClass; + if( type instanceof ParameterizedType ) + { + ParameterizedType pt = (ParameterizedType) type; + Type[] args = pt.getActualTypeArguments(); + Class clazz = (Class) pt.getRawType(); + TypeVariable[] vars = clazz.getTypeParameters(); + for( int i = 0; i < vars.length; i++ ) + { + TypeVariable var = vars[ i]; + Type mappedType = args[ i]; + mappings.put( var, mappedType ); + } + subClass = (Class) pt.getRawType(); + } + else + { + subClass = (Class) type; + } + + Type resolvedType = resolveTypeVariable( name, declaringClass, mappings, subClass ); + if( resolvedType != null ) + { + return resolvedType; + } + } + + return null; + } + + /** + * Get URI for a class. + * + * @param clazz class + * + * @return URI + * + * @throws NullPointerException if clazz is null + */ + @SuppressWarnings( "raw" ) + public static String toURI( final Class clazz ) + throws NullPointerException + { + return toURI( clazz.getName() ); + } + + /** + * Get URI for a class name. + * <p> + * Example: + * </p> + * <p> + * Class name com.example.Foo$Bar is converted to URI urn:qi4j:com.example.Foo-Bar + * </p> + * + * @param className class name + * + * @return URI + * + * @throws NullPointerException if className is null + */ + public static String toURI( String className ) + throws NullPointerException + { + className = normalizeClassToURI( className ); + return "urn:qi4j:type:" + className; + } + + /** + * Get class name from a URI + * + * @param uri URI + * + * @return class name + * + * @throws NullPointerException if uri is null + */ + public static String toClassName( String uri ) + throws NullPointerException + { + uri = uri.substring( "urn:qi4j:type:".length() ); + uri = denormalizeURIToClass( uri ); + return uri; + } + + public static String normalizeClassToURI( String className ) + { + return className.replace( '$', '-' ); + } + + public static String denormalizeURIToClass( String uriPart ) + { + return uriPart.replace( '-', '$' ); + } + + public static Specification<ModelDescriptor> modelTypeSpecification( final String className ) + { + return new Specification<ModelDescriptor>() + { + @Override + public boolean satisfiedBy( ModelDescriptor item ) + { + return matchesAny( new Specification<String>() + { + @Override + public boolean satisfiedBy( String item ) + { + return item.equals( className ); + } + }, map( new Function<Class<?>, String>() + { + @Override + public String map( Class<?> item ) + { + return item.getName(); + } + }, item.types() ) ); + } + }; + } + + @SuppressWarnings( "raw" ) + public static Specification<ModelDescriptor> exactTypeSpecification( final Class type ) + { + return new Specification<ModelDescriptor>() + { + @Override + public boolean satisfiedBy( ModelDescriptor item ) + { + return matchesAny( new Specification<Class<?>>() + { + @Override + public boolean satisfiedBy( Class<?> item ) + { + return item.equals( type ); + } + }, item.types() ); + } + }; + } + + @SuppressWarnings( "raw" ) + public static Specification<ModelDescriptor> assignableTypeSpecification( final Class type ) + { + return new Specification<ModelDescriptor>() + { + @Override + public boolean satisfiedBy( ModelDescriptor item ) + { + return matchesAny( new Specification<Class<?>>() + { + @Override + @SuppressWarnings( "unchecked" ) + public boolean satisfiedBy( Class<?> itemType ) + { + return !type.equals( itemType ) && type.isAssignableFrom( itemType ); + } + }, item.types() ); + } + }; + } + + @SuppressWarnings( "raw" ) + public static String toString( Iterable<? extends Class> type ) + { + StringBuilder builder = new StringBuilder(); + builder.append( "[" ); + boolean first = true; + for( Class c : type ) + { + if( !first ) + { + builder.append( "," ); + } + first = false; + builder.append( c.getSimpleName() ); + } + builder.append( "]" ); + return builder.toString(); + } + + public static Function<Type, String> toClassName() + { + return new Function<Type, String>() + { + @Override + public String map( Type type ) + { + return RAW_CLASS.map( type ).getName(); + } + }; + } + + private Classes() + { + } +}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/util/Constructors.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/util/Constructors.java b/core/api/src/main/java/org/apache/zest/api/util/Constructors.java new file mode 100644 index 0000000..440c6fb --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/util/Constructors.java @@ -0,0 +1,40 @@ +/* + * 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.zest.api.util; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Type; +import org.apache.zest.functional.Function; + +import static org.apache.zest.functional.Iterables.iterable; + +/** + * Useful methods for handling Constructors. + */ +public final class Constructors +{ + public static final Function<Type, Iterable<Constructor<?>>> CONSTRUCTORS_OF = Classes.forClassHierarchy( new Function<Class<?>, Iterable<Constructor<?>>>() + { + @Override + public Iterable<Constructor<?>> map( Class<?> type ) + { + return iterable( type.getDeclaredConstructors() ); + } + } ); +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/util/Dates.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/util/Dates.java b/core/api/src/main/java/org/apache/zest/api/util/Dates.java new file mode 100644 index 0000000..126c169 --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/util/Dates.java @@ -0,0 +1,102 @@ +/* + * Copyright 2009 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.api.util; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +/** + * Useful methods for handling Dates. + */ +public final class Dates +{ + // Formatters are not thread-safe. Create one per thread + private static final ThreadLocal<DateFormat> ISO8601 = new ThreadLocal<DateFormat>() + { + @Override + protected DateFormat initialValue() + { + return new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ" ); + } + }; + + private static final ThreadLocal<DateFormat> ISO8601_UTC = new ThreadLocal<DateFormat>() + { + @Override + protected DateFormat initialValue() + { + SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" ); + dateFormat.setTimeZone( TimeZone.getTimeZone( "UTC" ) ); + return dateFormat; + } + }; + + /** + * @param stringDate a string representing a date as either ISO8601, @millis@ or /Date() formats + * @return a Date + */ + public static Date fromString( String stringDate ) + { + try + { + Date date = ISO8601_UTC.get().parse( stringDate ); + return date; + } + catch( ParseException e ) + { + try + { + Date date = ISO8601.get().parse( stringDate ); + return date; + } + catch( ParseException e1 ) + { + // @millis@ format + if( stringDate.startsWith( "@" ) && stringDate.endsWith( "@" ) ) + { + long time = Long.parseLong( stringDate.substring( 1, stringDate.length() - 1 ) ); + Date date = new Date( time ); + return date; + } + else if( stringDate.startsWith( "/Date(" ) && stringDate.endsWith( ")/" ) ) // Microsoft format + { + long time = Long.parseLong( stringDate.substring( 6, stringDate.length() - 2 ) ); + Date date = new Date( time ); + return date; + } + throw new IllegalStateException( "Illegal date:" + stringDate ); + } + } + } + + /** + * @param date a Date + * @return String representation in ISO8601 UTC + */ + public static String toUtcString( Date date ) + { + return ISO8601_UTC.get().format( date ); + } + + private Dates() + { + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/util/Fields.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/util/Fields.java b/core/api/src/main/java/org/apache/zest/api/util/Fields.java new file mode 100644 index 0000000..e6ecced --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/util/Fields.java @@ -0,0 +1,51 @@ +/* + * 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.zest.api.util; + +import java.lang.reflect.Field; +import java.lang.reflect.Type; +import org.apache.zest.functional.Function; +import org.apache.zest.functional.Function2; +import org.apache.zest.functional.Iterables; + +import static org.apache.zest.functional.Iterables.iterable; + +/** + * Useful methods for handling Fields. + */ +public final class Fields +{ + public static final Function2<Class<?>, String, Field> FIELD_NAMED = new Function2<Class<?>, String, Field>() + { + @Override + public Field map( Class<?> aClass, String name ) + { + return Iterables.first( Iterables.filter( Classes.memberNamed( name ), FIELDS_OF.map( aClass ) ) ); + } + }; + + public static final Function<Type, Iterable<Field>> FIELDS_OF = Classes.forClassHierarchy( new Function<Class<?>, Iterable<Field>>() + { + @Override + public Iterable<Field> map( Class<?> type ) + { + return iterable( type.getDeclaredFields() ); + } + } ); +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/util/ListMap.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/util/ListMap.java b/core/api/src/main/java/org/apache/zest/api/util/ListMap.java new file mode 100644 index 0000000..57f0623 --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/util/ListMap.java @@ -0,0 +1,42 @@ +/* + * 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.api.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * Map whose values are Lists of things. Create + * one ArrayList for each key that is added. The list does not allow + * duplicates. + */ +public final class ListMap<K, V> + extends HashMap<K, List<V>> +{ + public void add( K key, V value ) + { + List<V> list = get( key ); + if( list == null ) + { + list = new ArrayList<V>(); + put( key, list ); + } + if( !list.contains( value ) ) + { + list.add( value ); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/util/Methods.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/util/Methods.java b/core/api/src/main/java/org/apache/zest/api/util/Methods.java new file mode 100644 index 0000000..f87d58f --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/util/Methods.java @@ -0,0 +1,50 @@ +/* + * 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.zest.api.util; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import org.apache.zest.functional.Function; +import org.apache.zest.functional.Specification; + +import static org.apache.zest.functional.Iterables.iterable; + +/** + * Useful methods for handling Methods. + */ +public class Methods +{ + public static final Specification<Type> HAS_METHODS = new Specification<Type>() + { + @Override + public boolean satisfiedBy( Type item ) + { + return Classes.RAW_CLASS.map( item ).getDeclaredMethods().length > 0; + } + }; + + public static final Function<Type, Iterable<Method>> METHODS_OF = Classes.forTypes( new Function<Type, Iterable<Method>>() + { + @Override + public Iterable<Method> map( Type type ) + { + return iterable( Classes.RAW_CLASS.map( type ).getDeclaredMethods() ); + } + } ); +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/util/NullArgumentException.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/util/NullArgumentException.java b/core/api/src/main/java/org/apache/zest/api/util/NullArgumentException.java new file mode 100644 index 0000000..2807ca3 --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/util/NullArgumentException.java @@ -0,0 +1,56 @@ +/* Copyright 2007 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.api.util; + +/** + * Thrown if an argument to a method was null, and the method required + * it to be non-null. + */ +public class NullArgumentException + extends IllegalArgumentException +{ + private static final long serialVersionUID = 4815431779868729780L; + + private NullArgumentException( String message ) + { + super( message ); + } + + public static void validateNotNull( String parameterName, Object value ) + { + if( value != null ) + { + return; + } + String message = parameterName + " was null."; + throw new NullArgumentException( message ); + } + + public static void validateNotEmpty( String parameterName, String value ) + { + if( value == null ) + { + String message = parameterName + " was null."; + throw new NullArgumentException( message ); + } + if( value.length() == 0 ) + { + String message = parameterName + " was empty."; + throw new NullArgumentException( message ); + } + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/util/package.html ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/util/package.html b/core/api/src/main/java/org/apache/zest/api/util/package.html new file mode 100644 index 0000000..ea75db3 --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/util/package.html @@ -0,0 +1,21 @@ +<!-- +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. +--> +<html> + <body> + <h2>API Utilities.</h2> + </body> +</html> http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/value/NoSuchValueException.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/value/NoSuchValueException.java b/core/api/src/main/java/org/apache/zest/api/value/NoSuchValueException.java new file mode 100644 index 0000000..754768a --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/value/NoSuchValueException.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2008, Niclas Hedhman. 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.api.value; + +import org.apache.zest.api.composite.NoSuchCompositeException; + +/** + * Thrown when no visible value of the requested type is found. + */ +public class NoSuchValueException + extends NoSuchCompositeException +{ + public NoSuchValueException( String valueType, String moduleName ) + { + super( "ValueComposite", valueType, moduleName ); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/value/ValueBuilder.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/value/ValueBuilder.java b/core/api/src/main/java/org/apache/zest/api/value/ValueBuilder.java new file mode 100644 index 0000000..c544ef0 --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/value/ValueBuilder.java @@ -0,0 +1,56 @@ +/* + * 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.api.value; + +import org.apache.zest.api.association.AssociationStateHolder; +import org.apache.zest.api.common.ConstructionException; + +/** + * Builder for Values. + */ +public interface ValueBuilder<T> +{ + AssociationStateHolder state(); + + /** + * Get a representation of the state for the new Value. + * It is possible to access and update properties and associations, + * even immutable ones since the builder represents the initial state. + * + * @return a mutable instance of the Value type + */ + T prototype(); + + /** + * Get a representation of the state of the given type for the new ValueComposite. + * This is primarily used if you want to provide state for a private mixin type. + * + * @param mixinType the mixin which you want to provide state for + * + * @return a proxy implementing the given mixin type + */ + <K> K prototypeFor( Class<K> mixinType ); + + /** + * Create a new Composite instance. + * + * @return a new Composite instance + * + * @throws org.apache.zest.api.common.ConstructionException + * thrown if it was not possible to instantiate the Composite + */ + T newInstance() + throws ConstructionException; +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/value/ValueBuilderFactory.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/value/ValueBuilderFactory.java b/core/api/src/main/java/org/apache/zest/api/value/ValueBuilderFactory.java new file mode 100644 index 0000000..062c3fd --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/value/ValueBuilderFactory.java @@ -0,0 +1,100 @@ +/* + * 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.api.value; + +import java.util.Map; +import org.apache.zest.api.association.AssociationDescriptor; +import org.apache.zest.api.common.ConstructionException; +import org.apache.zest.api.entity.EntityReference; +import org.apache.zest.api.property.PropertyDescriptor; +import org.apache.zest.functional.Function; + +/** + * Factory for Values and ValueBuilders. + */ +public interface ValueBuilderFactory +{ + + /** + * Instantiate a Value of the given type. + * + * @param valueType the Value type to instantiate + * + * @return a new Value instance + * + * @throws NoSuchValueException if no value extending the mixinType has been registered + * @throws ConstructionException if the value could not be instantiated + */ + <T> T newValue( Class<T> valueType ) + throws NoSuchValueException, ConstructionException; + + /** + * Create a builder for creating new Values that implements the given Value type. + * <p>The returned ValueBuilder can be reused to create several Values instances.</p> + * + * @param valueType an interface that describes the Composite to be instantiated + * + * @return a ValueBuilder for creation of ValueComposites implementing the interface + * + * @throws NoSuchValueException if no value extending the mixinType has been registered + */ + <T> ValueBuilder<T> newValueBuilder( Class<T> valueType ) + throws NoSuchValueException; + + /** + * Create a builder for creating a new Value starting with the given prototype. + * <p>The returned ValueBuilder can only be used ONCE.</p> + * + * @param prototype a prototype the builder will use + * + * @return a ValueBuilder for creation of ValueComposites implementing the interface of the prototype + * + * @throws NoSuchValueException if no value extending the mixinType has been registered + */ + <T> ValueBuilder<T> newValueBuilderWithPrototype( T prototype ); + + /** + * Create a builder for creating a new Value starting with the given state. + * <p>The returned ValueBuilder can only be used ONCE.</p> + * + * @param mixinType an interface that describes the Composite to be instantiated + * @param propertyFunction a function providing the state of properties + * @param associationFunction a function providing the state of associations + * @param manyAssociationFunction a function providing the state of many associations + * @param namedAssociationFunction a function providing the state of named associations + * + * @return a ValueBuilder for creation of ValueComposites implementing the interface + * + * @throws NoSuchValueException if no value extending the mixinType has been registered + */ + <T> ValueBuilder<T> newValueBuilderWithState( Class<T> mixinType, + Function<PropertyDescriptor, Object> propertyFunction, + Function<AssociationDescriptor, EntityReference> associationFunction, + Function<AssociationDescriptor, Iterable<EntityReference>> manyAssociationFunction, + Function<AssociationDescriptor, Map<String, EntityReference>> namedAssociationFunction ); + + /** + * Instantiate a Value of the given type using the serialized state given as String. + * + * @param valueType the Value type to instantiate + * @param serializedState the state of the Value + * + * @return a new Value instance + * + * @throws NoSuchValueException if no value extending the mixinType has been registered + * @throws ConstructionException if the value could not be instantiated + */ + <T> T newValueFromSerializedState( Class<T> valueType, String serializedState ); + +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/value/ValueBuilderTemplate.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/value/ValueBuilderTemplate.java b/core/api/src/main/java/org/apache/zest/api/value/ValueBuilderTemplate.java new file mode 100644 index 0000000..5860f4b --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/value/ValueBuilderTemplate.java @@ -0,0 +1,43 @@ +/* + * 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.zest.api.value; + +import org.apache.zest.api.structure.Module; + +/** + * Builder template for Values. + */ +public abstract class ValueBuilderTemplate<T> +{ + Class<T> type; + + protected ValueBuilderTemplate( Class<T> type ) + { + this.type = type; + } + + protected abstract void build( T prototype ); + + public T newInstance( Module module ) + { + ValueBuilder<T> builder = module.newValueBuilder( type ); + build( builder.prototype() ); + return builder.newInstance(); + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/value/ValueComposite.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/value/ValueComposite.java b/core/api/src/main/java/org/apache/zest/api/value/ValueComposite.java new file mode 100644 index 0000000..dff6264 --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/value/ValueComposite.java @@ -0,0 +1,43 @@ +/* + * 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.api.value; + +import org.apache.zest.api.association.AssociationMixin; +import org.apache.zest.api.association.ManyAssociationMixin; +import org.apache.zest.api.association.NamedAssociationMixin; +import org.apache.zest.api.composite.Composite; +import org.apache.zest.api.mixin.Mixins; +import org.apache.zest.api.property.Immutable; + +/** + * ValueComposites are Composites that has state, and equality is defined from its values and not any identity nor + * instance references. + * + * <ul> + * <li>No Identity</li> + * <li>No Lifecycle</li> + * <li>Immutable</li> + * <li>equals()/hashCode() operates on the Properties</li> + * <li>Can have property and associations methods.</li> + * <li>Can not reference Services</li> + * <li>Can not have @Uses</li> + * </ul> + */ +@Immutable +@Mixins( { AssociationMixin.class, ManyAssociationMixin.class, NamedAssociationMixin.class } ) +public interface ValueComposite + extends Composite +{ +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/value/ValueDescriptor.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/value/ValueDescriptor.java b/core/api/src/main/java/org/apache/zest/api/value/ValueDescriptor.java new file mode 100644 index 0000000..dbd424c --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/value/ValueDescriptor.java @@ -0,0 +1,32 @@ +/* + * 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.api.value; + +import org.apache.zest.api.association.AssociationStateDescriptor; +import org.apache.zest.api.composite.CompositeDescriptor; +import org.apache.zest.api.composite.StatefulCompositeDescriptor; +import org.apache.zest.api.type.ValueCompositeType; + +/** + * Descriptor for ValueComposites. + */ +public interface ValueDescriptor + extends CompositeDescriptor, StatefulCompositeDescriptor +{ + ValueCompositeType valueType(); + + @Override + AssociationStateDescriptor state(); +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/value/ValueDeserializer.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/value/ValueDeserializer.java b/core/api/src/main/java/org/apache/zest/api/value/ValueDeserializer.java new file mode 100644 index 0000000..abdd7d1 --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/value/ValueDeserializer.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2012, 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.api.value; + +import java.io.InputStream; +import org.apache.zest.api.type.ValueType; +import org.apache.zest.functional.Function; +import org.apache.zest.functional.Function2; + +/** + * Use a ValueDeserializer to create new values instances from serialized state. + * + * <p> + * Serialized state must be one of: + * </p> + * <ul> + * <li>a ValueComposite,</li> + * <li>an EntityReference,</li> + * <li>a Collection,</li> + * <li>a Map,</li> + * <li>a Plain Value.</li> + * </ul> + * <p> + * Nested plain values, EntityReferences, Collections, Maps, ValueComposites are supported. + * EntityReferences are deserialized as their identity string. + * </p> + * <p> + * Plain values can be one of: + * </p> + * <ul> + * <li>String,</li> + * <li>Character or char,</li> + * <li>Boolean or boolean,</li> + * <li>Integer or int,</li> + * <li>Long or long,</li> + * <li>Short or short,</li> + * <li>Byte or byte,</li> + * <li>Float or float,</li> + * <li>Double or double,</li> + * <li>BigInteger,</li> + * <li>BigDecimal,</li> + * <li>Date,</li> + * <li>DateTime (JodaTime),</li> + * <li>LocalDateTime (JodaTime),</li> + * <li>LocalDate (JodaTime).</li> + * </ul> + * <p> + * Values of unknown types and all arrays are considered as {@link java.io.Serializable} and by so are deserialized + * from base64 encoded bytes using pure Java serialization. If it happens that the input is invalid, a + * ValueSerializationException is thrown. + * </p> + * <p> + * Having type information in the serialized payload allows to keep actual ValueComposite types and by so + * circumvent {@link org.apache.zest.api.composite.AmbiguousTypeException} when deserializing. + * </p> + */ +public interface ValueDeserializer +{ + + /** + * Factory method for a typed deserialize function. + * + * <p>The returned Function may throw {@link ValueSerializationException}.</p> + * + * @param type the value type + * @param <T> the parametrized function return type + * @return a deserialization function + */ + <T> Function<String, T> deserialize( Class<T> type ); + + /** + * Factory method for a typed deserialize function. + * + * <p>The returned Function may throw {@link ValueSerializationException}.</p> + * + * @param valueType the value type + * @param <T> the parametrized function return type + * @return a deserialization function + */ + <T> Function<String, T> deserialize( ValueType valueType ); + + /** + * Factory method for an untyped deserialize function. + * + * <p>The returned Function may throw {@link ValueSerializationException}.</p> + * + * @param <T> the parametrized function return type + * @return a deserialization function + */ + <T> Function2<ValueType, String, T> deserialize(); + + /** + * Deserialize a value from a state. + * + * @param <T> the parametrized returned type + * @param type the value type + * @param input the state + * @return the value + * @throws ValueSerializationException if the deserialization failed + */ + <T> T deserialize( Class<?> type, String input ) + throws ValueSerializationException; + + /** + * Deserialize a value from a state. + * + * @param <T> the parametrized returned type + * @param valueType the value type + * @param input the state + * @return the value + * @throws ValueSerializationException if the deserialization failed + */ + <T> T deserialize( ValueType valueType, String input ) + throws ValueSerializationException; + + /** + * Deserialize a value from a state. + * + * @param <T> the parametrized returned type + * @param type the value type + * @param input the state stream + * @return the value + * @throws ValueSerializationException if the deserialization failed + */ + <T> T deserialize( Class<?> type, InputStream input ) + throws ValueSerializationException; + + /** + * Deserialize a value from a state. + * + * @param <T> the parametrized returned type + * @param valueType the value type + * @param input the state stream + * @return the value + * @throws ValueSerializationException if the deserialization failed + */ + <T> T deserialize( ValueType valueType, InputStream input ) + throws ValueSerializationException; +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/value/ValueSerialization.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/value/ValueSerialization.java b/core/api/src/main/java/org/apache/zest/api/value/ValueSerialization.java new file mode 100644 index 0000000..6a6809e --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/value/ValueSerialization.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2012, 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.api.value; + +/** + * ValueSerialization API. + * + * See {@link ValueSerializer} and {@link ValueDeserializer}. + */ +public interface ValueSerialization + extends ValueSerializer, ValueDeserializer +{ + + /** + * Serialization format @Service tags. + * + * <p> + * ValueSerialization implementations should be tagged with theses at assembly time so that consumers can + * specify which format they need. + * </p> + */ + interface Formats + { + + /** + * Tag a ValueSerialization service that support the JSON format. + */ + String JSON = "json"; + /** + * Tag a ValueSerialization service that support the XML format. + */ + String XML = "xml"; + /** + * Tag a ValueSerialization service that support the YAML format. + */ + String YAML = "yaml"; + } + +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/value/ValueSerializationException.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/value/ValueSerializationException.java b/core/api/src/main/java/org/apache/zest/api/value/ValueSerializationException.java new file mode 100644 index 0000000..39d1576 --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/value/ValueSerializationException.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012, 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.api.value; + +/** + * Thrown when an error occur during value state (de)serialization. + */ +public class ValueSerializationException + extends RuntimeException +{ + + private static final long serialVersionUID = 1L; + + public ValueSerializationException() + { + super(); + } + + public ValueSerializationException( String message ) + { + super( message ); + } + + public ValueSerializationException( String message, Throwable cause ) + { + super( message, cause ); + } + + public ValueSerializationException( Throwable cause ) + { + super( cause.getClass().getName() + ": " + cause.getMessage(), cause ); + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/value/ValueSerializer.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/value/ValueSerializer.java b/core/api/src/main/java/org/apache/zest/api/value/ValueSerializer.java new file mode 100644 index 0000000..26db5e2 --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/value/ValueSerializer.java @@ -0,0 +1,323 @@ +/* + * 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.api.value; + +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; +import org.apache.zest.api.composite.AmbiguousTypeException; +import org.apache.zest.functional.Function; + +/** + * Use a ValueSerializer to serialize values state. + * + * <p> + * Serialized object must be one of: + * </p> + * <ul> + * <li>a ValueComposite,</li> + * <li>an EntityComposite or EntityReference,</li> + * <li>an Iterable,</li> + * <li>a Map,</li> + * <li>a Plain Value.</li> + * </ul> + * <p> + * Nested plain values, EntityReferences, Iterables, Maps, ValueComposites and EntityComposites are supported. + * EntityComposites and EntityReferences are serialized as their identity string. + * </p> + * <p> + * Plain values can be one of: + * </p> + * <ul> + * <li>String,</li> + * <li>Character or char,</li> + * <li>Boolean or boolean,</li> + * <li>Integer or int,</li> + * <li>Long or long,</li> + * <li>Short or short,</li> + * <li>Byte or byte,</li> + * <li>Float or float,</li> + * <li>Double or double,</li> + * <li>BigInteger,</li> + * <li>BigDecimal,</li> + * <li>Date,</li> + * <li>DateTime (JodaTime),</li> + * <li>LocalDateTime (JodaTime),</li> + * <li>LocalDate (JodaTime).</li> + * </ul> + * <p> + * Values of unknown types and all arrays are considered as {@link java.io.Serializable} and by so are serialized to + * base64 encoded bytes using pure Java serialization. If it happens that the value is not Serializable, a + * ValueSerializationException is thrown. + * </p> + * <p> + * Having type information in the serialized payload allows to keep actual ValueComposite types and by so + * circumvent {@link AmbiguousTypeException} when deserializing. + * </p> + */ +public interface ValueSerializer +{ + + /** + * Factory method for a serialize function. + * + * @param <T> the parametrized function input type + * @return a serialization function. + */ + <T> Function<T, String> serialize(); + + /** + * Factory method for a serialize function. + * + * @param <T> the parametrized function input type + * @param options ValueSerializer Options + * @return a serialization function. + */ + <T> Function<T, String> serialize( Options options ); + + /** + * Factory method for a serialize function. + * + * @param <T> the parametrized function input type + * @param includeTypeInfo if type information should be included in the output + * @return a serialization function. + */ + @Deprecated + <T> Function<T, String> serialize( boolean includeTypeInfo ); + + /** + * Serialize the state of a value with type information. + * + * @param object an Object to serialize + * @return the state + * @throws ValueSerializationException if the Value serialization failed + */ + String serialize( Object object ) + throws ValueSerializationException; + + /** + * Serialize the state of a value. + * + * @param options ValueSerializer Options + * @param object an Object to serialize + * @return the state + * @throws ValueSerializationException if the Value serialization failed + */ + String serialize( Options options, Object object ) + throws ValueSerializationException; + + /** + * Serialize the state of a value. + * + * @param object an Object to serialize + * @param includeTypeInfo if type information should be included in the output + * @return the state + * @throws ValueSerializationException if the Value serialization failed + */ + @Deprecated + String serialize( Object object, boolean includeTypeInfo ) + throws ValueSerializationException; + + /** + * Serialize the state of a value with type information. + * + * @param object an Object to serialize + * @param output that will be used as output + * @throws ValueSerializationException if the Value serialization failed + */ + void serialize( Object object, OutputStream output ) + throws ValueSerializationException; + + /** + * Serialize the state of a value. + * + * @param options ValueSerializer Options + * @param object an Object to serialize + * @param output that will be used as output + * @throws ValueSerializationException if the Value serialization failed + */ + void serialize( Options options, Object object, OutputStream output ) + throws ValueSerializationException; + + /** + * Serialize the state of a value. + * + * @param object an Object to serialize + * @param output that will be used as output + * @param includeTypeInfo if type information should be included in the output + * @throws ValueSerializationException if the Value serialization failed + */ + @Deprecated + void serialize( Object object, OutputStream output, boolean includeTypeInfo ) + throws ValueSerializationException; + + /** + * Serialization options. + */ + final class Options + { + /** + * Boolean flag to include type information. + * Default to TRUE. + */ + public static final String INCLUDE_TYPE_INFO = "includeTypeInfo"; + public static final String MAP_ENTRIES_AS_OBJECTS = "mapentriesasobjects"; + private final Map<String, String> options = new HashMap<>(); + + /** + * Create new default ValueSerializer Options. + */ + public Options() + { + this.options.put( INCLUDE_TYPE_INFO, "true" ); + this.options.put( MAP_ENTRIES_AS_OBJECTS, "false" ); + } + + /** + * Set {@link #INCLUDE_TYPE_INFO} option to TRUE. + * @return This + */ + public Options withTypeInfo() + { + return put( INCLUDE_TYPE_INFO, true ); + } + + /** + * Set {@link #INCLUDE_TYPE_INFO} option to FALSE. + * @return This + */ + public Options withoutTypeInfo() + { + return put( INCLUDE_TYPE_INFO, false ); + } + + public Options withMapEntriesAsObjects() + { + return put( MAP_ENTRIES_AS_OBJECTS, true ); + } + + public Options withMapEntriesAsKeyValuePairs() + { + return put( MAP_ENTRIES_AS_OBJECTS, false ); + } + + /** + * Get Boolean option value. + * @param option The option + * @return The boolean value of the option, or null if absent + */ + public Boolean getBoolean( String option ) + { + if( !options.containsKey( option ) ) + { + return null; + } + return Boolean.valueOf( options.get( option ) ); + } + + /** + * Get Integer option value. + * @param option The option + * @return The integer value of the option, or null if absent + */ + public Integer getInteger( String option ) + { + if( !options.containsKey( option ) ) + { + return null; + } + return Integer.valueOf( options.get( option ) ); + } + + /** + * Get String option value. + * @param option The option + * @return The string value of the option, or null if absent + */ + public String getString( String option ) + { + return options.get( option ); + } + + /** + * Put an option String value. + * @param option The option + * @param value The value + * @return This Options instance + */ + public Options put( String option, String value ) + { + if( value == null ) + { + return remove( option ); + } + options.put( option, value ); + return this; + } + + /** + * Put an option boolean value. + * @param option The option + * @param value The value + * @return This Options instance + */ + public Options put( String option, Boolean value ) + { + if( value == null ) + { + return remove( option ); + } + options.put( option, Boolean.toString( value ) ); + return this; + } + + /** + * Put an option Integer value. + * @param option The option + * @param value The value + * @return This Options instance + */ + public Options put( String option, Integer value ) + { + if( value == null ) + { + return remove( option ); + } + options.put( option, value.toString() ); + return this; + } + + /** + * Remove an option value. + * @param option The option + * @return This Options instance + */ + public Options remove( String option ) + { + options.remove( option ); + return this; + } + + /** + * Get all defined options as a Map. + * @return All defined options in a new Map + */ + public Map<String, String> toMap() + { + return new HashMap<>( options ); + } + } +} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/apache/zest/api/value/package.html ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/value/package.html b/core/api/src/main/java/org/apache/zest/api/value/package.html new file mode 100644 index 0000000..540b3f6 --- /dev/null +++ b/core/api/src/main/java/org/apache/zest/api/value/package.html @@ -0,0 +1,21 @@ +<!-- +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. +--> +<html> + <body> + <h2>Value API.</h2> + </body> +</html> http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/qi4j/api/Qi4j.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/qi4j/api/Qi4j.java b/core/api/src/main/java/org/qi4j/api/Qi4j.java deleted file mode 100644 index cfd8a89..0000000 --- a/core/api/src/main/java/org/qi4j/api/Qi4j.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2007, 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.qi4j.api; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; -import org.qi4j.api.association.AbstractAssociation; -import org.qi4j.api.association.AssociationDescriptor; -import org.qi4j.api.composite.Composite; -import org.qi4j.api.composite.CompositeDescriptor; -import org.qi4j.api.composite.CompositeInstance; -import org.qi4j.api.composite.InvalidCompositeException; -import org.qi4j.api.composite.ModelDescriptor; -import org.qi4j.api.composite.TransientDescriptor; -import org.qi4j.api.entity.EntityDescriptor; -import org.qi4j.api.entity.Identity; -import org.qi4j.api.property.Property; -import org.qi4j.api.property.PropertyDescriptor; -import org.qi4j.api.service.ServiceDescriptor; -import org.qi4j.api.structure.Module; -import org.qi4j.api.value.ValueDescriptor; -import org.qi4j.functional.Function; - -/** - * Encapsulation of the Zest API. - */ -public interface Qi4j -{ - /** - * If a Modifier gets a reference to the Composite using @This, - * then that reference must be dereferenced using this method - * before handing it out for others to use. - * - * @param <T> Parameterized type of the Composite - * @param composite instance reference injected in Modified using @This - * - * @return the dereferenced Composite - */ - <T> T dereference( T composite ); - - /** - * Returns the Module or UnitOfWork where the Composite belongs. - * - * @param compositeOrUow The Composite (Service, Value, Entity or Transient) or UnitOfWork to lookup the Module it - * belongs to. - * - * @return The Module instance where the Composite or UnitOfWork belongs to. - */ - Module moduleOf( Object compositeOrUow ); - - /** - * Returns the ModelDescriptor of the Composite. - * - * @param compositeOrServiceReference The Composite (Service, Value, Entity or Transient) for which to lookup the - * ModelDescriptor - * - * @return The ModelDescriptor of the Composite - */ - ModelDescriptor modelDescriptorFor( Object compositeOrServiceReference ); - - /** - * Returns the CompositeDescriptor of the Composite. - * - * @param compositeOrServiceReference The Composite (Service, Value, Entity or Transient) for which to lookup the - * CompositeDescriptor - * - * @return The CompositeDescriptor of the Composite - */ - CompositeDescriptor compositeDescriptorFor( Object compositeOrServiceReference ); - - /** - * Returns the TransientDescriptor of the TransientComposite. - * - * @param transsient The TransientComposite for which to lookup the TransientDescriptor - * - * @return The TransientDescriptor of the TransientComposite - */ - TransientDescriptor transientDescriptorFor( Object transsient ); - - /** - * Returns the EntityDescriptor of the EntityComposite. - * - * @param entity The EntityComposite for which to lookup the EntityDescriptor - * - * @return The EntityDescriptor of the EntityComposite - */ - EntityDescriptor entityDescriptorFor( Object entity ); - - /** - * Returns the ValueDescriptor of the ValueComposite. - * - * @param value The ValueComposite for which to lookup the ValueDescriptor - * - * @return The ValueDescriptor of the ValueComposite - */ - ValueDescriptor valueDescriptorFor( Object value ); - - /** - * Returns the ServiceDescriptor of the ServiceComposite. - * - * @param service The ServiceComposite for which to lookup the ServiceDescriptor - * - * @return The ServiceDescriptor of the ServiceComposite - */ - ServiceDescriptor serviceDescriptorFor( Object service ); - - /** - * Returns the PropertyDescriptor of the Property. - * - * @param property The Property for which to lookup the PropertyDescriptor - * - * @return The PropertyDescriptor of the Property - */ - PropertyDescriptor propertyDescriptorFor( Property<?> property ); - - /** - * Returns the AssociationDescriptor of the Association. - * - * @param association The Association for which to lookup the AssociationDescriptor - * - * @return The AssociationDescriptor of the Association - */ - AssociationDescriptor associationDescriptorFor( AbstractAssociation association ); - - /** - * Function that returns the CompositeDescriptor of a Composite. - */ - Function<Composite, CompositeDescriptor> FUNCTION_DESCRIPTOR_FOR = new Function<Composite, CompositeDescriptor>() - { - @Override - public CompositeDescriptor map( Composite composite ) - { - if( composite instanceof Proxy ) - { - InvocationHandler invocationHandler = Proxy.getInvocationHandler( composite ); - return ( (CompositeInstance) invocationHandler ).descriptor(); - } - try - { - Class<? extends Composite> compositeClass = composite.getClass(); - Field instanceField = compositeClass.getField( "_instance" ); - Object instance = instanceField.get( composite ); - return ( (CompositeInstance) instance ).descriptor(); - } - catch( Exception e ) - { - InvalidCompositeException exception = new InvalidCompositeException( "Could not get _instance field" ); - exception.initCause( e ); - throw exception; - } - } - }; - - /** - * Function that returns the CompositeInstance of a Composite. - */ - Function<Composite, CompositeInstance> FUNCTION_COMPOSITE_INSTANCE_OF = new Function<Composite, CompositeInstance>() - { - @Override - public CompositeInstance map( Composite composite ) - { - if( composite instanceof Proxy ) - { - return ( (CompositeInstance) Proxy.getInvocationHandler( composite ) ); - } - try - { - Class<? extends Composite> compositeClass = composite.getClass(); - Field instanceField = compositeClass.getField( "_instance" ); - Object instance = instanceField.get( composite ); - return (CompositeInstance) instance; - } - catch( Exception e ) - { - InvalidCompositeException exception = new InvalidCompositeException( "Could not get _instance field" ); - exception.initCause( e ); - throw exception; - } - } - }; -} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/qi4j/api/activation/Activation.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/qi4j/api/activation/Activation.java b/core/api/src/main/java/org/qi4j/api/activation/Activation.java deleted file mode 100644 index 32f26e4..0000000 --- a/core/api/src/main/java/org/qi4j/api/activation/Activation.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2011, Rickard Ãberg. - * Copyright (c) 2012, Niclas Hedhman. - * 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.qi4j.api.activation; - -/** - * Interface used by Structure elements and Services that can be activated and passivated. - * <p>Application and Layer expose this interface so you can activate and passivate them.</p> - * <p>Module and ServiceComposite activation/passivation is handled by the Zest runtime.</p> - */ -public interface Activation -{ - /** - * Activate. - * <p>Fail fast execution order is:</p> - * <ul> - * <li>Fire {@link ActivationEvent.EventType#ACTIVATING}</li> - * <li>Call {@link Activator#beforeActivation(java.lang.Object)} on each Activator</li> - * <li>Call {@link #activate()} children</li> - * <li>Call {@link Activator#afterActivation(java.lang.Object)} on each Activator</li> - * <li>Fire {@link ActivationEvent.EventType#ACTIVATED}</li> - * </ul> - * <p>If an Exception is thrown, already activated nodes are passivated.</p> - * @throws ActivationException with first Exception of activation plus the PassivationException if any - */ - void activate() - throws ActivationException; - - /** - * Passivate. - * <p>Fail safe execution order is:</p> - * <ul> - * <li>Fire {@link ActivationEvent.EventType#PASSIVATING}</li> - * <li>Call {@link Activator#beforePassivation(java.lang.Object)} on each Activator</li> - * <li>Call {@link #passivate()} children</li> - * <li>Call {@link Activator#afterPassivation(java.lang.Object)} on each Activator</li> - * <li>Fire {@link ActivationEvent.EventType#PASSIVATED}</li> - * </ul> - * @throws PassivationException after passivation with all Exceptions of passivation if any - */ - void passivate() - throws PassivationException; -} http://git-wip-us.apache.org/repos/asf/zest-java/blob/8744a67f/core/api/src/main/java/org/qi4j/api/activation/ActivationEvent.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/qi4j/api/activation/ActivationEvent.java b/core/api/src/main/java/org/qi4j/api/activation/ActivationEvent.java deleted file mode 100644 index 1852251..0000000 --- a/core/api/src/main/java/org/qi4j/api/activation/ActivationEvent.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2011, Rickard Ãberg. - * Copyright (c) 2012, 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.qi4j.api.activation; - -/** - * ActivationEvents are fired during activation and passivation of instances in Zest. - */ -public final class ActivationEvent -{ - public enum EventType - { - ACTIVATING, ACTIVATED, PASSIVATING, PASSIVATED - } - - private final long timestamp; - private final Object source; - private final EventType type; - - public ActivationEvent( Object source, EventType type ) - { - this.timestamp = System.currentTimeMillis(); - this.source = source; - this.type = type; - } - - /** - * @return the source of the Activation event - */ - public Object source() - { - return source; - } - - /** - * @return the type of the Activation event - */ - public EventType type() - { - return type; - } - - /** - * @return an informative message describing the event - */ - public String message() - { - switch( type ) - { - case ACTIVATING: - return "Activating " + source; - case ACTIVATED: - return "Activated " + source; - case PASSIVATING: - return "Passivating " + source; - case PASSIVATED: - return "Passivated " + source; - } - return ""; - } - - /** - * @see #message() - */ - @Override - public String toString() - { - return message(); - } -} \ No newline at end of file
