/*
* Copyright 2013 Cameron Beccario
*
* 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 net.nullschool.grains;
import net.nullschool.collect.ConstMap;
import static net.nullschool.collect.basic.BasicCollections.*;
/**
* 2013-03-25<p/>
*
* Utility methods for operating on grains.
*
* @author Cameron Beccario
*/
public final class GrainTools {
private GrainTools() {
throw new AssertionError();
}
/**
* Returns the target package for the specified schema. The target package is the package where generated grain
* classes are located by convention. If the {@link GrainSchema#targetPackage targetPackage} attribute has been
* defined, then that value is returned. Otherwise, the package of the schema itself is returned.<p/>
*
* If {@code schema} has not been annotated with {@link GrainSchema}, this method returns null.
*
* @param schema the schema to get the target package for.
* @return the package as a dot-delimited string, or null if the class is not a grain schema.
* @throws NullPointerException if schema is null.
*/
public static String targetPackageOf(Class<?> schema) {
GrainSchema annotation = schema.getAnnotation(GrainSchema.class);
if (annotation == null) {
return null;
}
return !annotation.targetPackage().isEmpty() ? annotation.targetPackage() : schema.getPackage().getName();
}
private static GrainFactory factoryInstance(Class<? extends GrainFactory> clazz) {
if (clazz.isEnum()) {
// @SuppressWarnings("unchecked") Object instance = Enum.valueOf((Class<? extends Enum>)clazz, "INSTANCE");
Object instance = clazz.getEnumConstants()[0];
return (GrainFactory)instance;
}
throw new IllegalArgumentException(
"expected factory implementation to follow enum singleton pattern: " + clazz);
}
public static GrainFactory factoryFor(Class<?> clazz) {
// UNDONE: this throws if factory cannot be found, but targetPackageOf returns null if package cannot be found.
// CONSIDER: also possible to check if the enclosing class is a GrainFactory, like would be for *GrainImpl.
GrainFactoryRef ref = clazz.getAnnotation(GrainFactoryRef.class);
if (ref != null) {
return factoryInstance(ref.value());
}
if (GrainFactory.class.isAssignableFrom(clazz)) {
return factoryInstance(clazz.asSubclass(GrainFactory.class));
}
// CONSIDER: also map GrainSchemas to their factories? would need a ClassLoader as optional parameter.
throw new IllegalArgumentException("cannot find factory for " + clazz);
}
/**
* Returns a map of property names to property descriptors built from the specified array of property descriptors.
* Each property's name becomes its associated key in the resulting map.
*
* @param properties the properties to build the map from.
* @return an immutable map of names to property descriptors.
* @throws NullPointerException if the array is null or contains null.
*/
public static ConstMap<String, GrainProperty> asPropertyMap(GrainProperty... properties) {
String[] keys = new String[properties.length];
for (int i = 0; i < properties.length; i++) {
keys[i] = properties[i].getName();
}
return asMap(keys, properties);
}
}