All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bridje.orm.impl.OrmServiceImpl Maven / Gradle / Ivy

/*
 * Copyright 2016 Bridje Framework.
 *
 * 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.bridje.orm.impl;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.bridje.ioc.Component;
import org.bridje.ioc.Inject;
import org.bridje.ioc.impl.ClassUtils;
import org.bridje.ioc.thls.Thls;
import org.bridje.ioc.thls.ThlsAction;
import org.bridje.ioc.thls.ThlsActionException;
import org.bridje.ioc.thls.ThlsActionException2;
import org.bridje.jdbc.JdbcService;
import org.bridje.orm.DataSourcesSetup;
import org.bridje.orm.DbObject;
import org.bridje.orm.Entity;
import org.bridje.orm.EntityContext;
import org.bridje.orm.OrmModel;
import org.bridje.orm.OrmService;
import org.bridje.orm.SQLDialect;
import org.bridje.orm.Table;
import org.bridje.orm.TableColumn;

@Component
class OrmServiceImpl implements OrmService
{
    private static final Logger LOG = Logger.getLogger(OrmServiceImpl.class.getName());

    public static final String ENTITYS_RESOURCE_FILE = "BRIDJE-INF/orm/entities.properties";

    private Map, TableImpl> tablesMap;

    private Map, List>> modelsEntitysMap;

    private Map, List>> modelsTablesMap;

    @Inject
    private JdbcService jdbcServ;
    
    @Inject
    private SQLDialect[] dialects;

    @PostConstruct
    public void init()
    {
        this.tablesMap = new HashMap<>();
        try
        {
            createTables();
            createModelsEntitys();
        }
        catch (IOException e)
        {
            LOG.log(Level.SEVERE, e.getMessage(), e);
        }
    }

    @Override
    public  T createModel(String dsName, Class modelCls)
    {
        EntityContext ctx = createContext(dsName);
        return instantiateModel(ctx, modelCls);
    }

    @Override
    public  T createModel(DataSource ds, Class modelCls)
    {
        EntityContext ctx = createContext(ds);
        return instantiateModel(ctx, modelCls);
    }

    @Override
    public  T createModel(EntityContext ctx, Class modelCls)
    {
        return instantiateModel(ctx, modelCls);
    }

    private EntityContext createContext(String dsName)
    {
        return createContext(jdbcServ.getDataSource(dsName));
    }

    private EntityContext createContext(DataSource ds)
    {
        if(ds == null)
        {
            throw new IllegalArgumentException("No datasource was specified.");
        }
        for (SQLDialect dialect : dialects)
        {
            if(dialect.canHandle(ds))
            {
                return new EntityContextImpl(this, ds, dialect);
            }
        }
        throw new IllegalArgumentException("Can´t find a valid dialect for this DataSource");
    }
    
    @Override    
    public boolean isEntityClass(Class cls)
    {
        return this.tablesMap.containsKey(cls);
    }
    
    @Override
    public  TableImpl findTable(Class entity)
    {
        TableImpl result = (TableImpl)this.tablesMap.get(entity);
        if(result == null)
        {
            throw new IllegalArgumentException(entity.getName() + " is not an entity class.");
        }
        return result;
    }

    @Override
    public  Class findModelClass(Class entity)
    {
        Entity annotation = entity.getAnnotation(Entity.class);
        if(annotation == null)
        {
            throw new IllegalArgumentException(entity.getName() + " is not an entity class.");
        }
        return annotation.model();
    }

    @Override
    public  List> findEntitys(Class modelClass)
    {
        return Collections.unmodifiableList(modelsEntitysMap.get(modelClass));
    }

    @Override
    public  List> findTables(Class modelClass)
    {
        return Collections.unmodifiableList(modelsTablesMap.get(modelClass).stream().map(t -> (TableImpl)t).collect(Collectors.toList()));
    }

    private void createModelsEntitys() throws IOException
    {
        modelsEntitysMap = new HashMap<>();
        tablesMap.forEach((e, t) -> addEntityToModel(e));
        modelsTablesMap = new HashMap<>();
        tablesMap.forEach((e, t) -> addTableToModel(e, t));
    }
    
    private void addEntityToModel(Class entityClass)
    {
        Entity annotation = entityClass.getAnnotation(Entity.class);
        List> lst = modelsEntitysMap.get(annotation.model());
        if(lst == null)
        {
            lst = new ArrayList<>();
            modelsEntitysMap.put(annotation.model(), lst);
        }
        lst.add(entityClass);
    }
    
    private void addTableToModel(Class entityClass, TableImpl table)
    {
        Entity annotation = entityClass.getAnnotation(Entity.class);
        List> lst = modelsTablesMap.get(annotation.model());
        if(lst == null)
        {
            lst = new ArrayList<>();
            modelsTablesMap.put(annotation.model(), lst);
        }
        lst.add(table);
    }

    private void createTables() throws IOException
    {
        List files = findModelsFiles();
        files.stream()
                .map((url) -> readFile(url))
                .forEach((prop) -> prop.forEach(this::createTable));
        injectDbObjects();
        tablesMap.forEach((k, v) -> v.initRelations(this));
    }

    private List findModelsFiles() throws IOException
    {
        List urls = new ArrayList<>();
        Enumeration resources = Thread.currentThread().getContextClassLoader().getResources(ENTITYS_RESOURCE_FILE);
        while (resources.hasMoreElements())
        {
            URL nextElement = resources.nextElement();
            urls.add(nextElement);
        }
        return urls;
    }

    private Properties readFile(URL url)
    {
        Properties prop = new Properties();
        try (InputStream is = url.openStream())
        {
            prop.load(is);
        }
        catch(IOException ex)
        {
            LOG.log(Level.SEVERE, ex.getMessage(), ex);
        }
        return prop;
    }

    private void createTable(Object objClsName, Object objTableName)
    {
        try
        {
            String clsName = (String)objClsName;
            String tableName = (String)objTableName;
            Class cls = Class.forName(clsName);
            findOrAddTableEntity(cls, tableName);
        }
        catch (ClassNotFoundException e)
        {
            LOG.log(Level.SEVERE, e.getMessage(), e);
        }
    }

    private  TableImpl findOrAddTableEntity(Class entityClass, String tableName)
    {
        if(!tablesMap.containsKey(entityClass))
        {
            tablesMap.put(entityClass, new TableImpl<>(entityClass, tableName));
        }
        return (TableImpl) tablesMap.get(entityClass);
    }

    private void injectDbObjects()
    {
        tablesMap.forEach((entity, table) -> this.injectDbObject(entity));
    }

    private void injectDbObject(Class entity)
    {
        try
        {
            Field[] fields = entity.getDeclaredFields();
            for (Field field : fields)
            {
                DbObject dbObject = field.getAnnotation(DbObject.class);
                if (Modifier.isStatic(field.getModifiers()) 
                        && dbObject != null)
                {
                    if(field.getType().equals(Table.class))
                    {
                        Type param = ClassUtils.parameterType(field.getGenericType(), 0);
                        if(param != null)
                        {
                            field.set(null, findTable(ClassUtils.rawClass(param)));
                        }
                    }
                    else if(TableColumn.class.isAssignableFrom(field.getType()))
                    {
                        Type param = ClassUtils.parameterType(field.getGenericType(), 0);
                        if(param != null)
                        {
                            TableImpl tb = findTable(ClassUtils.rawClass(param));
                            if(tb != null)
                            {
                                field.set(null, tb.findColumn(dbObject.value()));
                            }
                        }                        
                    }
                }
            }
        }
        catch (SecurityException | IllegalArgumentException | IllegalAccessException e)
        {
            LOG.log(Level.SEVERE, e.getMessage(), e);
        }
    }

    private  T instantiateModel(EntityContext ctx, Class modelCls)
    {
        try
        {
            Constructor constructor = modelCls.getDeclaredConstructor(EntityContext.class, List.class, List.class);
            if(constructor != null)
            {
                constructor.setAccessible(true);
                return constructor.newInstance(ctx, findEntitys(modelCls), findTables(modelCls));
            }
        }
        catch (NoSuchMethodException | SecurityException 
                | IllegalAccessException | IllegalArgumentException 
                | InvocationTargetException | InstantiationException ex)
        {
            LOG.log(Level.SEVERE, ex.getMessage(), ex);
        }
        return null;
    }

    @Override
    public  T doWithModels(ThlsAction action, DataSourcesSetup setup)
    {
        return Thls.doAs(action, ModelsThlsProvider.class, new ModelsThlsProvider(setup, this));
    }

    @Override
    public  T doWithModelsEx(ThlsActionException action, DataSourcesSetup setup) throws E
    {
        return Thls.doAsEx(action, ModelsThlsProvider.class, new ModelsThlsProvider(setup, this));
    }

    @Override
    public  T doWithModelsEx2(ThlsActionException2 action, DataSourcesSetup setup) throws E, E2
    {
        return Thls.doAsEx2(action, ModelsThlsProvider.class, new ModelsThlsProvider(setup, this));
    }

    @Override
    public  T getModel(Class modelClass)
    {
        return Thls.get(ModelsThlsProvider.class).getModel(modelClass);
    }

    @Override
    public OrmModel getModelForEntity(Class entityClass)
    {
        Class modelCls = findModelClass(entityClass);
        return getModel(modelCls);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy