Project: b3log-latke
/*
 * Copyright (c) 2009, 2010, 2011, 2012, B3log Team 
 * 
 * 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.b3log.latke.repository.jpa; 
 
import java.lang.reflect.Field; 
import java.util.Map; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import javax.persistence.EntityManager; 
import javax.persistence.EntityTransaction; 
import javax.persistence.FlushModeType; 
import javax.persistence.Id; 
import javax.persistence.LockModeType; 
import javax.persistence.Query; 
import org.b3log.latke.Keys; 
import org.b3log.latke.model.User; 
import org.b3log.latke.repository.Repositories; 
import org.b3log.latke.repository.Repository; 
import org.b3log.latke.repository.Transaction; 
import org.json.JSONObject; 
 
/**
 * Entity manager implementation. 
 * 
 * @author <a href="mailto:DL88250@gmail.com">Liang Ding</a> 
 * @version 1.0.0.0, Oct 10, 2011 
 */
 
public final class EntityManagerImpl implements EntityManager { 
 
    /**
     * Logger. 
     */
 
    private static final Logger LOGGER = Logger.getLogger(EntityManagerImpl.class.getName()); 
 
    @Override 
    public void persist(final Object entity) { 
        final Class<? extends Object> clazz = entity.getClass(); 
        final MetaEntity metaEntity = Entities.getMetaEntity(clazz); 
        if (null == metaEntity) { 
            throw new IllegalArgumentException("The specified object[class=" + clazz + ",toString=" 
                                               + entity.toString() + "] is not an entity"); 
        } 
 
        final String repositoryName = metaEntity.getRepositoryName(); 
        final Repository repository = Repositories.getRepository(repositoryName); 
        if (null == repository) { 
            throw new IllegalArgumentException("The specified object[class=" + clazz + ",toString=" 
                                               + entity.toString() + "] is not an entity"); 
        } 
 
        try { 
            final JSONObject jsonObject = toJSONObject(entity); 
            repository.add(jsonObject); 
        } catch (final Exception e) { 
            // XXX: maybe a transaction required exception.... 
            final String errMsg = "Can not persist entity[class=" + clazz + ",toString=" + entity.toString() + "]"
            LOGGER.log(Level.SEVERE, errMsg, e); 
 
            throw new IllegalArgumentException(errMsg); 
        } 
    } 
 
    /**
     * Converts the specified entity to a json object. 
     *  
     * @param entity the specified entity 
     * @return json object 
     * @throws Exception exception 
     */
 
    private JSONObject toJSONObject(final Object entity) throws Exception { 
        final JSONObject ret = new JSONObject(); 
 
        final Class<? extends Object> clazz = entity.getClass(); 
        final MetaEntity metaEntity = Entities.getMetaEntity(clazz); 
 
        final Map<String, Field> fields = metaEntity.getFields(); 
        for (final Map.Entry<String, Field> entityField : fields.entrySet()) { 
            final String fieldName = entityField.getKey(); 
            final Field field = entityField.getValue(); 
            final Class<?> fieldType = field.getType(); 
            field.setAccessible(true); 
            final Object fieldValue = field.get(entity); 
 
            if (field.isAnnotationPresent(Id.class)) { 
                if (null != fieldValue) { 
                    ret.put(Keys.OBJECT_ID, fieldValue); 
                } 
 
                continue
            } 
 
            if (fieldType.isPrimitive() || String.class.equals(fieldType)) { 
                ret.put(fieldName, fieldValue); 
            } 
 
            // TODO: relationships handling 
        } 
 
        return ret; 
    } 
 
    @Override 
    public <T> T merge(final T entity) { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public void remove(final Object entity) { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public <T> T find(final Class<T> entityClass, final Object primaryKey) { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public <T> T getReference(final Class<T> entityClass, 
                              final Object primaryKey) { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public void flush() { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public void setFlushMode(final FlushModeType flushMode) { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public FlushModeType getFlushMode() { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public void lock(final Object entity, final LockModeType lockMode) { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public void refresh(final Object entity) { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public void clear() { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public boolean contains(final Object entity) { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public Query createQuery(final String qlString) { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public Query createNamedQuery(final String name) { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public Query createNativeQuery(final String sqlString) { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public Query createNativeQuery(final String sqlString, 
                                   final Class resultClass) { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public Query createNativeQuery(final String sqlString, 
                                   final String resultSetMapping) { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public void joinTransaction() { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public Object getDelegate() { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public void close() { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    @Override 
    public boolean isOpen() { 
        throw new UnsupportedOperationException("Not supported yet."); 
    } 
 
    /**
     * {@inheritDoc} 
     *  
     * <p> 
     * Invokes this method to begin a transaction, this method MUST be invoked 
     * once before invoking {@link #persist(java.lang.Object) persist(entity)},  
     * {@link #merge(java.lang.Object) merge(entity)} or  
     * {@link #remove(java.lang.Object) remove(entity)}, and  
     * {@link EntityTransaction#commit() commit()} or  
     * {@link EntityTransaction#rollback() rollback()} this transaction after 
     * operations. 
     * </p> 
     *  
     * <p> 
     * <b>Note</b>: The returned entity transaction has been began, so should  
     * not invoke it's method {@link EntityTransaction#begin() begin()} again. 
     * </p> 
     *  
     * @return  
     */
 
    @Override 
    public EntityTransaction getTransaction() { 
        // The user repository is a Latke built-in repository 
        final Repository userRepository = Repositories.getRepository(User.USER); 
        final Transaction transaction = userRepository.beginTransaction(); 
 
        return new EntityTransactionImpl(transaction); 
    } 
}