Java tutorial
/* * Copyright 2007-2008 the original author or authors. * * 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 ae.config; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.Sets.newHashSet; import static org.apache.commons.lang.StringUtils.isBlank; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ae.config.field.IndexableField; import ae.config.field.MetaBlobField; import ae.config.field.MetaBooleanField; import ae.config.field.MetaCategoryField; import ae.config.field.MetaDateField; import ae.config.field.MetaDoubleField; import ae.config.field.MetaEmailField; import ae.config.field.MetaEnumField; import ae.config.field.MetaField; import ae.config.field.MetaKeyField; import ae.config.field.MetaListField; import ae.config.field.MetaLongField; import ae.config.field.MetaPhoneNumberField; import ae.config.field.MetaPostalAddressField; import ae.config.field.MetaReferenceField; import ae.config.field.MetaSetField; import ae.config.field.MetaStringField; import ae.config.field.MetaTextField; import ae.config.field.MetaUserField; import com.google.common.base.Preconditions; /** * Describes the <a href="http://martinfowler.com/eaaCatalog/activeRecord.html">Active Record</a> to be generated. * <p> * At the moment only covers modeling <a href="http://martinfowler.com/eaaCatalog/activeRecord.html"> Active Record</a> wrapping the possibilities of * <a href="https://developers.google.com/appengine/docs/java/datastore/">Datastore</a> defined in <a href = * "https://developers.google.com/appengine/">AppEngine</a>. Thus, the possible configurations are: * <ul> * <li><em>Super Class</em>: base class used to generate the described ActiveEntity.</li> * <li><em>Package Name</em>: package java where it has to generate the described ActiveEntity.</li> * <li><em>Kind</em>: kind of <a href="https://developers.google.com/appengine/docs/java/datastore/entities">entity</a> accessed by the described * ActiveEntity.</li> * <li><em>Fields</em>: default fields defined in the <a href="https://developers.google.com/appengine/docs/java/datastore/entities">entity</a> * accessed by the described ActiveEntity.</li> * </ul> * </p> */ public class ActiveEntity { private static final Logger logger = LoggerFactory.getLogger(ActiveEntity.class); /** Project in which this model is defined. <code>null</code> by default. */ private Project project; /** Complete package where the defined ae should be generated. Can not be <code>null</code>. */ private String packageName; /** Defined ae canonnical superclass name. Can not be <code>null</code>. */ private String superClass; /** Defined ae entity kind. If <code>null</code> adopts the value of <code>this.className</code>. */ private String kind; /** Properties declared in the defined ae. Can not be <code>null</code>, but it can be empty. */ private final Set<MetaField<?>> fields = newHashSet(); private final Set<IndexableField<?>> indexedFields = newHashSet(); /** * Configures the Kind of <a href="https://developers.google.com/appengine/docs/java/datastore/entities">entity</a> to be wrapped. * * @param desiredEntityKind * the desired entity kind * @throws NullPointerException * if desiredEntityKind is <code>null</code>. * @throws IllegalArgumentException * if desiredEntityKind is whitespace, empty (<code>""</code>) or <code>null</code>. */ protected void kind(final String desiredEntityKind) { checkNotNull(desiredEntityKind, "desiredEntityKind"); checkArgument(!isBlank(desiredEntityKind), "desiredEntityKind is blank"); this.kind = desiredEntityKind; } /** * Configures the java package where the resulting class will be created. * * @param desiredJavaPackageName * the desired java package where to define the generated class. * @throws NullPointerException * if desiredJavaPackageName is <code>null</code>. */ protected void packageName(final String desiredJavaPackageName) { checkNotNull(desiredJavaPackageName, "desiredJavaPackageName"); this.packageName = desiredJavaPackageName; } /** * Configures the super class of the resulting class. * * @param desiredSuperClass * class to be used as super Class. * @throws NullPointerException * if desiredSuperClass is <code>null</code>. */ protected void superClass(final Class<?> desiredSuperClass) { checkNotNull(desiredSuperClass, "desiredSuperClass"); superClass(desiredSuperClass.getCanonicalName()); } /** * Configures the super class name of the resulting class. * * @param desiredSuperClassName * canonical name of the class to be used as super Class. * @throws NullPointerException * if desiredSuperClassName is <code>null</code>. */ protected void superClass(final String desiredSuperClassName) { checkNotNull(desiredSuperClassName, "desiredSuperClassName"); this.superClass = desiredSuperClassName; } public String getPackageName() { return this.packageName; } public boolean isPackageDefined() { return !isBlank(getPackageName()); } public String getSuperClass() { return this.superClass; } public String getClassName() { return getClass().getSimpleName(); } public String getKind() { return this.kind; } public Set<MetaField<?>> getFields() { return this.fields; } public Set<IndexableField<?>> getIndexedFields() { return this.indexedFields; } public Project getProject() { return this.project; } public void prepareWith(final Project project) { checkNotNull(project, "project"); logger.info("project for [ActiveEntity: {}] defined", getClassName()); this.project = project; prepareKind(); preparePackageName(); prepareSuperClass(); prepareFields(); } void prepareKind() { if (isBlank(this.kind)) { this.kind = getClass().getSimpleName(); } logger.info("{}.kind = {}", getClassName(), this.kind); } void preparePackageName() { if (isBlank(this.packageName)) { this.packageName = this.project.getDefaultPackage(); } logger.info("{}.packageName = {}", getClassName(), this.packageName); } void prepareSuperClass() { if (this.superClass == null) { superClass(this.project.getDefaultSuperClass()); } logger.info("{}.superClass = {}", getClassName(), this.superClass); } protected void prepareFields() { for (final java.lang.reflect.Field javafield : getClass().getDeclaredFields()) { javafield.setAccessible(true); if (declaresField(javafield)) { final MetaField<?> activeEntityField = readFieldAt(javafield); activeEntityField.prepareField(javafield.getName()); addField(activeEntityField); } } } boolean declaresField(final java.lang.reflect.Field field) { assert field != null : "field is null"; if (!def.class.isAssignableFrom(field.getType())) { return false; } final Object definition = readDefinitionAt(field); return definition != null; } MetaField<?> readFieldAt(final java.lang.reflect.Field field) { assert field != null : "field is null"; final MetaField<?> declaredField = getFieldOn(field); return declaredField; } MetaField<?> getFieldOn(final java.lang.reflect.Field field) { assert field != null : "field is null"; return def.class.cast(readDefinitionAt(field)).asMetaField(); } Object readDefinitionAt(final java.lang.reflect.Field field) { final Object definition; try { definition = field.get(this); } catch (final IllegalAccessException e) { throw new IllegalStateException(e); } return definition; } public boolean hasJavaPackage() { return !isBlank(this.packageName); } public String getIdType() { return "long"; } public void addField(final MetaField<?> field) { Preconditions.checkNotNull(field, "field"); if (field instanceof IndexableField) { addIndexableField((IndexableField<?>) field); } else { addNotIndexableField(field); } } private void addNotIndexableField(final MetaField<?> field) { this.fields.add(field); } private void addIndexableField(final IndexableField<?> field) { this.fields.add(field); if (field.isIndexed()) { this.indexedFields.add(field); } } protected final MetaBlobField.Builder.Factory BlobField = new MetaBlobField.Builder.Factory(this); protected final MetaBooleanField.Builder.Factory BooleanField = new MetaBooleanField.Builder.Factory(this); protected final MetaCategoryField.Builder.Factory CategoryField = new MetaCategoryField.Builder.Factory(this); protected final MetaDateField.Builder.Factory DateField = new MetaDateField.Builder.Factory(this); protected final MetaEmailField.Builder.Factory EmailField = new MetaEmailField.Builder.Factory(this); protected final <E extends Enum<E>> MetaEnumField.Builder EnumField(final Class<E> enumClass) { return new MetaEnumField.Builder(this, enumClass); } protected final MetaEnumField.Builder EnumField(final String enumClassName) { return new MetaEnumField.Builder(this, enumClassName); } protected final MetaKeyField.Builder.Factory KeyField = new MetaKeyField.Builder.Factory(this); protected final MetaListField.Builder ListField(final Class<?> elementClass) { return new MetaListField.Builder(this, elementClass); } protected final MetaListField.Builder ListField(final String elementClassName) { return new MetaListField.Builder(this, elementClassName); } protected final MetaLongField.Builder.Factory LongField = new MetaLongField.Builder.Factory(this); protected final MetaDoubleField.Builder.Factory DoubleField = new MetaDoubleField.Builder.Factory(this); protected final MetaPhoneNumberField.Builder.Factory PhoneNumberField = new MetaPhoneNumberField.Builder.Factory( this); protected final MetaPostalAddressField.Builder.Factory PostalAddressField = new MetaPostalAddressField.Builder.Factory( this); protected final MetaUserField.Builder.Factory UserField = new MetaUserField.Builder.Factory(this); protected final MetaReferenceField.Builder ReferenceField( final Class<? extends ActiveEntity> referencedActiveEntity) { return new MetaReferenceField.Builder(this, referencedActiveEntity); } protected final MetaSetField.Builder SetField(final Class<?> elementClass) { return new MetaSetField.Builder(this, elementClass); } protected final MetaSetField.Builder SetField(final String elementClassName) { return new MetaSetField.Builder(this, elementClassName); } protected final MetaStringField.Builder.Factory StringField = new MetaStringField.Builder.Factory(this); protected final MetaTextField.Builder.Factory TextField = new MetaTextField.Builder.Factory(this); public boolean isIndexed() { return false; } public boolean isConstraintsDefined() { for (final MetaField<?> field : fields) { if (field.isConstraintsDefined()) { return true; } } return false; } }