/* * Copyright (C) 2003-2011 eXo Platform SAS. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.etk.model.api; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import java.util.Set; import org.etk.common.logging.Logger; import org.etk.model.core.EntitySession; import org.etk.model.plugins.entity.binder.ObjectBinder; import org.etk.model.plugins.entity.binding.EntityBinding; import org.etk.orm.api.BuilderException; import org.etk.reflect.api.ClassTypeInfo; /** * Created by The eXo Platform SAS * Author : eXoPlatform * exo@exoplatform.com * Jul 14, 2011 */ public abstract class EntityBuilder { /** . */ private static final Logger log = Logger.getLogger(EntityBuilder.class.getName()); /** The domain classes. */ private final Set<Class<?>> classes; /** . */ private boolean initialized; /** For stuff that need to happen under synchronization. */ private final Object lock = new Object(); public EntityBuilder() { this.initialized = false; this.classes = new HashSet<Class<?>>(); } /** * Adds a class definition. * * @param clazz the class to add * @throws NullPointerException if the provided class is null * @throws IllegalStateException if the builder is already initialized */ public void add(Class<?> clazz) throws NullPointerException, IllegalStateException { add(clazz, new Class<?>[0]); } /** * Adds a class definition. * * @param first the first class to add * @param other the other classes to add * @throws NullPointerException if the provided class is null * @throws IllegalStateException if the builder is already initialized */ public void add(Class<?> first, Class<?>... other) throws NullPointerException, IllegalStateException { if (first == null) { throw new NullPointerException(); } if (other == null) { throw new NullPointerException(); } Set<Class<?>> toAdd = new HashSet<Class<?>>(1 + other.length); toAdd.add(first); for (Class<?> clazz : other) { if (clazz == null) { throw new IllegalArgumentException("No array containing a null class accepted"); } toAdd.add(clazz); } synchronized (lock) { if (initialized) { throw new IllegalStateException("Cannot add a class to an initialized builder"); } classes.addAll(toAdd); } } /** * Create and return an instance of the builder. * * @return the EntityBuilder instance */ public static EntityBuilder create() { ServiceLoader<EntityBuilder> loader = ServiceLoader.load(EntityBuilder.class); Iterator<EntityBuilder> i = loader.iterator(); Throwable throwable = null; while (i.hasNext()) { try { EntityBuilder builder = i.next(); log.debug("Found EntityBuilder implementation " + builder.getClass().getName()); return builder; } catch (ServiceConfigurationError error) { if (throwable == null) { throwable = error; } log.debug("Could not load EntityBuilder implementation, will use next provider", error); } } throw new BuilderException("Could not instanciate builder", throwable); } /** * Builds the runtime and return a configured {@link org.etk.sample.model.EntityManager} instance. * * @param config the configuration to use * @return the EntityManager instance * @throws BuilderException any builder exception */ public final EntitySession build() throws BuilderException { // Init if needed init(); // return boot(); } /** * Initialize the builder, this operation should be called once per builder, unlike the {@link #build(Configuration)} * operation that can be called several times with different configurations. This operation is used to perform the * initialization that is common to any configuration such as building the meta model from the classes. * * @return whether or not initialization occured * @throws BuilderException any exception that would prevent the initialization to happen correctly */ public final boolean init() throws BuilderException { // Init if needed synchronized (lock) { if (!initialized) { init(classes); initialized = true; return true; } else { return false; } } } /** * Resolver these classes to prepare for mapping * @param classes * @throws BuilderException */ protected abstract void init(Set<Class<?>> classes) throws BuilderException; protected abstract EntitySession boot() throws BuilderException; public abstract Set<ClassTypeInfo> getClassInfoTypes(); public abstract Collection<EntityBinding> getBindings(); public abstract Collection<ObjectBinder<?>> getBinders(); }