com.wavemaker.runtime.data.task.AbstractReadTask.java Source code

Java tutorial

Introduction

Here is the source code for com.wavemaker.runtime.data.task.AbstractReadTask.java

Source

/*
 *  Copyright (C) 2012-2013 CloudJee, Inc. All rights reserved.
 *
 *  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 com.wavemaker.runtime.data.task;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Order;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Property;
import org.hibernate.type.Type;

import com.wavemaker.common.util.ObjectAccess;
import com.wavemaker.common.util.Tuple;
import com.wavemaker.runtime.data.DataServiceLoggers;
import com.wavemaker.runtime.data.DataServiceMetaData;
import com.wavemaker.runtime.data.Task;
import com.wavemaker.runtime.data.util.DataServiceConstants;
import com.wavemaker.runtime.data.util.DataServiceUtils;
import com.wavemaker.runtime.service.OrderBy;
import com.wavemaker.runtime.service.PagingOptions;
import com.wavemaker.runtime.service.ServiceConstants;

/**
 * @author Simon Toens
 */
public abstract class AbstractReadTask extends BaseTask implements Task {

    private interface PropertyTraversal {

        boolean keepGoing(Type type);
    }

    private static final PropertyTraversal NOOP_PROPERTY_TRAVERSAL = new PropertyTraversal() {

        @Override
        public boolean keepGoing(Type type) {
            return true;
        }
    };

    private static final PropertyTraversal COMPONENT_PROPERTY_TRAVERSAL = new PropertyTraversal() {

        @Override
        public boolean keepGoing(Type type) {
            return !type.isComponentType();
        }
    };

    private static final String ROOT_CRITERIA_KEY = "";

    protected Criteria initCriteriasMap(Map<String, Criteria> criterias, Class<?> rootType, Session session) {
        Criteria rtn = session.createCriteria(rootType);
        if (DataServiceLoggers.taskLogger.isDebugEnabled()) {
            DataServiceLoggers.taskLogger.debug("Created root criteria for " + rootType.getName());
        }
        criterias.put(ROOT_CRITERIA_KEY, rtn);
        return rtn;
    }

    protected Criteria getRootCriteria(Map<String, Criteria> criterias) {
        return criterias.get(ROOT_CRITERIA_KEY);
    }

    protected void fetch(Criteria criteria, String propertyName) {
        criteria.setFetchMode(propertyName, FetchMode.JOIN);
    }

    protected Criteria getCriteriaForPath(String path, Map<String, Criteria> criterias) {
        return getCriteriaForPath(path, criterias, false);
    }

    protected Criteria getCriteriaForPath(String path, Map<String, Criteria> criterias, boolean fetch) {

        Criteria rtn = criterias.get(path);
        if (rtn != null) {
            return rtn;
        }

        // find parent, and create a new one
        Tuple.Two<String, String> p = splitPath(path);
        Criteria parent = getCriteriaForPath(p.v1, criterias);

        rtn = parent.createCriteria(p.v2);

        if (fetch) {
            fetch(parent, p.v2);
        }

        criterias.put(path, rtn);

        return rtn;
    }

    protected Tuple.Two<String, String> splitPath(String path) {
        String parent = ROOT_CRITERIA_KEY;
        String child = path;
        int i = path.lastIndexOf(ServiceConstants.PROPERTY_SEP);
        if (i > -1) {
            parent = path.substring(0, i);
            child = path.substring(i + 1);
        }
        return Tuple.tuple(parent, child);
    }

    protected void applyPaging(PagingOptions options, Criteria c) {

        if (options == null) {
            return;
        }

        Long firstResult = options.getFirstResult();
        if (firstResult != null) {
            c.setFirstResult(firstResult.intValue());
        }
        Long maxResults = options.getMaxResults();
        if (maxResults != null) {
            c.setMaxResults(maxResults.intValue());
        }

        // this options instance can be re-used for the next page
        options.nextPage();
    }

    protected static void applyPaging(PagingOptions options, Query q) {

        if (options == null) {
            return;
        }

        Long firstResult = options.getFirstResult();
        if (firstResult != null) {
            q.setFirstResult(firstResult.intValue());
        }
        Long maxResults = options.getMaxResults();
        if (maxResults != null) {
            q.setMaxResults(maxResults.intValue());
        }

        // this options instance can be re-used for the next page
        options.nextPage();
    }

    protected void applyOrderBy(PagingOptions options, Map<String, Criteria> criterias) {

        if (options == null) {
            return;
        }

        if (options.getOrderByList().isEmpty()) {
            // get root criteria and add default ordering
            getRootCriteria(criterias).addOrder(Order.asc("id"));
            return;
        }

        for (OrderBy orderBy : options.getOrderByList()) {

            String orderByExp = orderBy.getPropertyPath();

            // rightmost part of path is the property we want to order by
            // rest is the path to the Criteria instance
            Tuple.Two<String, String> t = splitPath(orderByExp);
            Criteria c = getCriteriaForPath(t.v1, criterias);

            Order o = null;
            if (orderBy.isAsc()) {
                o = Order.asc(t.v2);
            } else {
                o = Order.desc(t.v2);
            }

            if (DataServiceLoggers.taskLogger.isDebugEnabled()) {
                DataServiceLoggers.taskLogger.debug("Added order by " + orderBy);
            }

            c.addOrder(o);
        }

    }

    protected String[] splitPropertyPath(String propertyPath) {
        String[] rtn = null;
        if (propertyPath.indexOf(DataServiceConstants.PROP_SEP) == -1) {
            rtn = new String[] { propertyPath };
        } else {
            rtn = propertyPath.split("\\" + DataServiceConstants.PROP_SEP);
        }
        return rtn;
    }

    protected Class<?> getPropertyType(Class<?> rootType, String propertyPath, String dbName) {
        Property p = getProperty(rootType, propertyPath, NOOP_PROPERTY_TRAVERSAL, dbName);
        Type hbmType = p.getType();
        return hbmType.getReturnedClass();
    }

    protected boolean isComponentType(Class<?> rootType, String propertyPath, String dbName) {
        Property p = getProperty(rootType, propertyPath, COMPONENT_PROPERTY_TRAVERSAL, dbName);
        return p == null;
    }

    protected boolean isNulleable(Class<?> rootType, String propertyPath, String dbName) {
        Property p = getProperty(rootType, propertyPath, NOOP_PROPERTY_TRAVERSAL, dbName);
        if (isRelatedMany(p.getType().getReturnedClass())) {
            return true;
        }
        return ((Column) p.getColumnIterator().next()).isNullable();
    }

    protected void logQuery(String query) {
        logQuery(query, Collections.<String, Object>emptyMap());
    }

    protected void logQuery(String query, Map<String, Object> bindParams) {
        if (DataServiceLoggers.taskLogger.isInfoEnabled()) {
            DataServiceLoggers.taskLogger.info(query);
            if (!bindParams.isEmpty()) {
                DataServiceLoggers.taskLogger.debug(bindParams);
            }
        }
    }

    protected Object runQuery(Query query, boolean singleResult, String dbName) {

        if (singleResult) {
            return query.uniqueResult();
        } else {

            List<?> rs = query.list();

            SessionFactory sessFact = getSessionFactory(dbName);
            Type[] returnTypes = query.getReturnTypes();
            Class<?> returnedClass = returnTypes[0].getReturnedClass();
            String[] propertyNames = sessFact.getClassMetadata(returnedClass).getPropertyNames();
            Type[] propertyTypes = sessFact.getClassMetadata(returnedClass).getPropertyTypes();

            ObjectAccess oa = ObjectAccess.getInstance();

            //
            // To eliminate possible duplicates and construct a new list
            // with orders preserved for the final results
            //
            Iterator<?> rsItr = rs.iterator();
            List<Object> finalResultSet = new ArrayList<Object>();
            while (rsItr.hasNext()) {
                Object obj = rsItr.next();
                if (finalResultSet.contains(obj)) {
                    continue;
                }

                for (int i = 0; i < propertyTypes.length; i++) {
                    if (propertyTypes[i].getName().contains("lob")
                            || propertyTypes[i].getName().toLowerCase().contains("binary")) {
                        oa.setProperty(obj, propertyNames[i], null);
                    }
                }
                finalResultSet.add(obj);
            }

            return finalResultSet;
        }
    }

    private Property getProperty(Class<?> rootType, String propertyPath, PropertyTraversal traversalStrategy,
            String dbName) {

        Property rtn = null;

        DataServiceMetaData m = getMetaData(dbName);

        String entityName = rootType.getName();

        SessionFactory fac = getSessionFactory(dbName);

        for (String s : splitPropertyPath(propertyPath)) {

            rtn = m.getProperty(entityName, s);

            Type hbmType = rtn.getType();

            if (!traversalStrategy.keepGoing(hbmType)) {
                return null;
            }

            entityName = DataServiceUtils.getJavaTypeName(hbmType, fac);
        }

        return rtn;
    }

}