com.quinsoft.zeidon.objectdefinition.ViewOd.java Source code

Java tutorial

Introduction

Here is the source code for com.quinsoft.zeidon.objectdefinition.ViewOd.java

Source

/**
This file is part of the Zeidon Java Object Engine (Zeidon JOE).
    
Zeidon JOE is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
Zeidon JOE 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 Lesser General Public License for more details.
    
You should have received a copy of the GNU Lesser General Public License
along with Zeidon JOE.  If not, see <http://www.gnu.org/licenses/>.
    
Copyright 2009-2012 QuinSoft
 */
/**
 *
 */
package com.quinsoft.zeidon.objectdefinition;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import com.quinsoft.zeidon.Application;
import com.quinsoft.zeidon.ObjectConstraintException;
import com.quinsoft.zeidon.ObjectConstraintType;
import com.quinsoft.zeidon.ObjectEngine;
import com.quinsoft.zeidon.Task;
import com.quinsoft.zeidon.TaskQualification;
import com.quinsoft.zeidon.UnknownViewEntityException;
import com.quinsoft.zeidon.UnknownViewOdException;
import com.quinsoft.zeidon.View;
import com.quinsoft.zeidon.ZeidonException;
import com.quinsoft.zeidon.dbhandler.DbHandler;
import com.quinsoft.zeidon.domains.Domain;
import com.quinsoft.zeidon.standardoe.ScalaHelper;
import com.quinsoft.zeidon.utils.JoeUtils;
import com.quinsoft.zeidon.utils.PortableFileReader;
import com.quinsoft.zeidon.utils.PortableFileReader.PortableFileAttributeHandler;
import com.quinsoft.zeidon.utils.PortableFileReader.PortableFileEntityHandler.NullEntityHandler;

/**
 * @author DG
 *
 */
public class ViewOd implements PortableFileAttributeHandler {
    private final Application app;
    private String name;
    private final String filename;
    private final Map<String, ViewEntity> nameMap = new HashMap<String, ViewEntity>();
    private List<ViewEntity> entityList = new ArrayList<ViewEntity>();
    private String erDate;
    private boolean hasGenKey;
    private String genkeyHandler;
    private String database;
    private boolean activateConstraint;
    private boolean commitConstraint;
    private String constraintOper;
    private int height = 0;
    private LockingLevel lockingLevel = LockingLevel.NONE;
    private SourceFileType sourceFileType = SourceFileType.VML;

    static private final Class<?>[] constructorArgTypes = new Class<?>[] { View.class };
    static private final Class<?>[] constructorArgTypes2 = new Class<?>[] { Task.class };

    public ViewOd(Task task, Application app, String name) throws UnknownViewOdException {
        super();
        this.app = app;
        this.name = name;

        // Make sure the XOD exists.
        String xod = name + ".XOD";

        // We know that system apps XODs are stored as all lower-case.
        if (app.isSystemApp())
            xod = xod.toLowerCase();

        filename = app.getObjectDir() + "/" + xod;
        InputStream inputStream = JoeUtils.getInputStream(task, filename, getClass().getClassLoader());
        if (inputStream == null)
            throw new UnknownViewOdException(name, filename, app);

        loadViewOD(task, inputStream);
    }

    public Application getApplication() {
        return app;
    }

    public String getName() {
        return name;
    }

    /**
     * Returns the full filename of the XOD that defined this OD.
     * @return XOD file name
     */
    public String getFileName() {
        return filename;
    }

    public ViewEntity getViewEntity(String entityName, boolean required) {
        // We allow the dbhandler to use a special string to indicate the
        // root.
        if (StringUtils.equals(entityName, DbHandler.ROOT_ENTITY))
            return getViewEntity(0); // Return the root view entity.

        ViewEntity viewEntity = nameMap.get(entityName);
        if (viewEntity == null && required)
            throw new UnknownViewEntityException(this, entityName);

        return viewEntity;
    }

    public ViewEntity getViewEntity(String entityName) {
        return getViewEntity(entityName, true);
    }

    public ViewEntity getViewEntity(int index) {
        ViewEntity viewEntity = entityList.get(index);
        return viewEntity;
    }

    private void loadViewOD(Task task, InputStream file) {
        try {
            PortableFileReader.ReadPortableFile(file, task.log(), new ViewOdHandler(this));
            task.log().info("View OD %s loaded from: %s", this, filename);
        } catch (Exception e) {
            throw ZeidonException.wrapException(e).prependFilename(filename);
        }
    }

    private void addViewEntity(ViewEntity viewEntity) {
        nameMap.put(viewEntity.getName(), viewEntity);
        height = Math.max(height, viewEntity.getLevel());
        entityList.add(viewEntity);
    }

    @Override
    public void setAttribute(PortableFileReader reader) {
        if (reader.getAttributeName().equals("NAME")) {
            if (!reader.getAttributeValue().equalsIgnoreCase(name))
                throw new ZeidonException("Name of object from XOD ('%s') doesn't match OD name",
                        reader.getAttributeValue());

            // Override the name used when this object was being created with the one from the .xod file.
            // We need to do this because names are case-insensitive and the user may have used a different
            // case than the one from the file.
            name = reader.getAttributeValue().intern();
        } else if (reader.getAttributeName().equals("ER_DATE")) {
            erDate = reader.getAttributeValue().intern();
        } else if (reader.getAttributeName().equals("DATABASE") || reader.getAttributeName().equals("DFT_DBNAME")) {
            database = reader.getAttributeValue().intern();
        } else if (reader.getAttributeName().equals("DBH_Data")) {
            // We don't actually use DBH_Data in JOE but this code is here because we need to
            // read past the blob data.
            int lth = Integer.parseInt(reader.getAttributeValue());
            byte[] buffer = new byte[lth];
            try {
                reader.getStreamReader().read(buffer, lth);
            } catch (Throwable e) {
                throw ZeidonException.wrapException(e);
            }
        }
        if (reader.getAttributeName().equals("GKHANDLER")) {
            genkeyHandler = reader.getAttributeValue().intern();
        } else if (reader.getAttributeName().equals("LOCK")) {
            Integer level = Integer.getInteger(reader.getAttributeValue());
            lockingLevel = LockingLevel.lookup(level);
        } else if (reader.getAttributeName().equals("OCEOPER")) {
            constraintOper = reader.getAttributeValue().intern();
        } else if (reader.getAttributeName().equals("OCACT")) {
            activateConstraint = reader.getAttributeValue().startsWith("Y");
        } else if (reader.getAttributeName().equals("OCCOM")) {
            commitConstraint = reader.getAttributeValue().startsWith("Y");
        } else if (reader.getAttributeName().equals("OCSRCTYPE")) {
            sourceFileType = SourceFileType.parse(reader.getAttributeValue());
        }
    }

    public List<ViewEntity> getViewEntitiesHier() {
        return entityList;
    }

    public int getEntityCount() {
        return entityList.size();
    }

    @Override
    public String toString() {
        return getApplication().toString() + "." + name;
    }

    public String getErDate() {
        return erDate;
    }

    public String getDatabase() {
        return database;
    }

    public ViewEntity getRoot() {
        return entityList.get(0);
    }

    /**
     * Traces the ViewOd to the log
     * @param task
     */
    public void displayViewOD(TaskQualification task) {
        task.log().info("Displaying View OD for %s", getName());
        for (ViewEntity viewEntity : getViewEntitiesHier()) {
            task.log().info("%s %d, count = %d", viewEntity.getName(), viewEntity.getLevel(),
                    viewEntity.getChildCount());
            for (ViewAttribute attrib : viewEntity.getAttributes()) {
                Domain domain = attrib.getDomain();
                String type = domain == null ? attrib.getType().toString() : domain.getName();
                task.log().info("    Attrib: %s %d Domain:%s", attrib.getName(), attrib.getAttributeNumber(), type);
            }

            DataRecord dataRecord = viewEntity.getDataRecord();
            if (dataRecord == null)
                continue;

            task.log().info("    DataRecord: %s type=%s", dataRecord.getRecordName(), dataRecord.getType());
            RelRecord relRecord = dataRecord.getRelRecord();
            if (relRecord == null)
                continue;

            task.log().info("    RelRecord: %s  type=%s", relRecord.getRecordName(),
                    relRecord.getRelationshipType());
            for (RelField relField : relRecord.getRelFields()) {
                task.log().info("        RelField: %s, %d, %d", relField.getFieldName(), relField.getRelToken(),
                        relField.getSrcToken());
            }
        }
    }

    void setHasGenKey(boolean hasGenKey) {
        this.hasGenKey = hasGenKey;
    }

    public boolean hasGenKey() {
        return hasGenKey;
    }

    public boolean hasActivateConstraint() {
        return activateConstraint;
    }

    public boolean hasCommitConstraint() {
        return commitConstraint;
    }

    private Object getConstraintObject(View view) {
        ObjectEngine oe = view.getObjectEngine();
        String className = getApplication().getPackage() + "." + getName() + "_Object";
        try {
            ClassLoader classLoader = oe.getClassLoader(className);
            Class<?> operationsClass;
            operationsClass = classLoader.loadClass(className);
            try {
                // First try with View as the constructor args.
                Constructor<?> constructor = operationsClass.getConstructor(constructorArgTypes);
                return constructor.newInstance(view);
            } catch (NoSuchMethodException e) {
                try {
                    // Maybe with a task constructor?
                    Constructor<?> constructor = operationsClass.getConstructor(constructorArgTypes2);
                    return constructor.newInstance(view.getTask());
                } catch (NoSuchMethodException e2) {
                    // Now try with an empty constructor.
                    Constructor<?> constructor = operationsClass.getConstructor();
                    return constructor.newInstance();
                }
            }
        } catch (Exception e) {
            throw ZeidonException.wrapException(e).prependViewOd(ViewOd.this)
                    .appendMessage("Class name = %s", className)
                    .appendMessage("See inner exception for more info.");
        }

    }

    static private final Class<?>[] ARGUMENT_TYPES1 = new Class<?>[] { View.class, Integer.class, Integer.class };
    static private final Class<?>[] ARGUMENT_TYPES2 = new Class<?>[] { View.class, ObjectConstraintType.class };

    private int executeConstraint(View view, ObjectConstraintType type) {
        if (getSourceFileType() == SourceFileType.SCALA)
            return executeScalaConstraint(view, type);

        Object object = getConstraintObject(view);

        try {
            Method method;
            try {
                method = object.getClass().getMethod(getConstraintOper(), ARGUMENT_TYPES1);
                Integer rc = (Integer) method.invoke(object, view, type.getVmlValue(), 0);
                return rc;
            } catch (NoSuchMethodException e1) {
                method = object.getClass().getMethod(getConstraintOper(), ARGUMENT_TYPES2);
                Integer rc = (Integer) method.invoke(object, view, type);
                return rc;
            }
        } catch (Exception e) {
            throw ZeidonException.wrapException(e).appendMessage("Class = %s", object.getClass().getCanonicalName())
                    .appendMessage("Method name = %s", getConstraintOper());
        }
    }

    @SuppressWarnings("unchecked")
    private int executeScalaConstraint(View view, ObjectConstraintType type) {
        String className = "com.quinsoft.zeidon.scala.ScalaHelperImpl";
        ObjectEngine oe = view.getObjectEngine();
        ClassLoader classLoader = oe.getClassLoader(className);
        Class<ScalaHelper> operationsClass;
        try {
            operationsClass = (Class<ScalaHelper>) classLoader.loadClass(className);
        } catch (ClassNotFoundException e) {
            throw new ZeidonException("Couldn't load %s.  Do you have zeidon-scala in your classpath?", className);
        }

        try {
            ScalaHelper instance = operationsClass.newInstance();
            return instance.executeObjectConstraint(view, type, classLoader);
        } catch (Exception e) {
            throw ZeidonException.wrapException(e);
        }
    }

    /**
     * Executes the activate constraint on the view.
     *
     * @param view
     * @return
     */
    public int executeActivateConstraint(View view) throws ObjectConstraintException {
        if (!hasActivateConstraint())
            return 0;

        try {
            return executeConstraint(view, ObjectConstraintType.ACTIVATE);
        } catch (Exception e) {
            throw ZeidonException.prependMessage(e, "Error calling Activate constraint for %s", this);
        }
    }

    /**
     * Executes the commit constraint on the view.
     *
     * @param view
     * @return
     */
    public int executeCommitConstraint(View view) throws ObjectConstraintException {
        if (!hasCommitConstraint())
            return 0;

        try {
            return executeConstraint(view, ObjectConstraintType.COMMIT);
        } catch (Exception e) {
            throw ZeidonException.prependMessage(e, "Error calling Commit constraint for %s", this);
        }
    }

    public String getConstraintOper() {
        return constraintOper;
    }

    private class ViewOdHandler extends NullEntityHandler {
        private final ViewOd viewOd;
        private ViewEntity currentViewEntity = null;
        private final ArrayList<ViewEntity> parentStack = new ArrayList<ViewEntity>();

        ViewOdHandler(ViewOd viewOd) {
            super();
            this.viewOd = viewOd;
            parentStack.add(null);
        }

        @Override
        public PortableFileAttributeHandler createEntity(PortableFileReader reader, int level, long flags) {
            if (reader.getAttributeName().equals("ATTRIB")) {
                ViewAttribute attrib = new ViewAttribute(currentViewEntity);
                return attrib;
            } else if (reader.getAttributeName().equals("CHILDENTITY")
                    || reader.getAttributeName().equals("ENTITY")) {
                // Subtract one from level to take into account that the level 1 entity
                // is the object name.
                level--;

                if (currentViewEntity != null)
                    addViewEntity(currentViewEntity);

                ViewEntity viewEntity = new ViewEntity(viewOd, level);

                if (level >= parentStack.size())
                    parentStack.add(viewEntity);
                else
                    parentStack.set(level, viewEntity);
                if (level > 1)
                    viewEntity.setParent(parentStack.get(level - 1));

                if (currentViewEntity != null)
                    currentViewEntity.setNextHier(viewEntity);
                viewEntity.setPrevHier(currentViewEntity);
                currentViewEntity = viewEntity;
                return viewEntity;
            } else if (reader.getAttributeName().equals("DATAFIELD")) {
                DataField dataField = new DataField();
                currentViewEntity.getDataRecord().addDataField(dataField);
                return dataField;
            } else if (reader.getAttributeName().equals("RELFIELD")) {
                RelField relField = new RelField();
                currentViewEntity.getDataRecord().getRelRecord().addRelField(relField);
                return relField;
            } else if (reader.getAttributeName().equals("RELRECORD")) {
                RelRecord relRecord = new RelRecord(currentViewEntity.getDataRecord());
                currentViewEntity.getDataRecord().setRelRecord(relRecord);
                return relRecord;
            } else if (reader.getAttributeName().equals("DATARECORD")) {
                DataRecord dataRecord = new DataRecord(currentViewEntity);
                currentViewEntity.setDataRecord(dataRecord);
                return dataRecord;
            } else if (reader.getAttributeName().equals("OBJECT")) {
                return viewOd;
            } else
                throw new ZeidonException("Unknown entity '%s'", reader.getAttributeValue());
        }

        @Override
        public void endEntity(PortableFileReader reader, PortableFileAttributeHandler handler, int level) {
            if (handler instanceof ViewEntity) {
                ViewEntity viewEntity = (ViewEntity) handler;

                // Count up the number of persistent and work attributes.
                int persistentCount = 0;
                int workCount = 0;
                for (ViewAttribute viewAttribute : viewEntity.getAttributes()) {
                    if (viewAttribute.isPersistent())
                        persistentCount++;
                    else
                        workCount++;
                }

                viewEntity.setPersistentAttributeCount(persistentCount);
                viewEntity.setWorkAttributeCount(workCount);
            } else if (handler instanceof ViewAttribute) {
                ViewAttribute attrib = (ViewAttribute) handler;
                currentViewEntity.addViewAttribute(attrib);
            }
        }

        @Override
        public void endFile() {
            addViewEntity(currentViewEntity); // Add the last view entity.

            // Set the sibling pointers for all the view entities.
            entityList.get(0).setSiblingsForChildren();
            entityList = Collections.unmodifiableList(entityList);
            Map<Integer, ViewAttribute> attribMap = new HashMap<Integer, ViewAttribute>();

            // Find the ViewAttrib for each of the DataFields.
            for (ViewEntity ve : entityList) {
                for (ViewAttribute viewAttrib : ve.getAttributes()) {
                    attribMap.put(viewAttrib.getToken(), viewAttrib);
                }

                DataRecord dataRecord = ve.getDataRecord();
                if (dataRecord != null) {
                    for (DataField dataField : dataRecord.dataFields()) {
                        ViewAttribute viewAttrib = attribMap.get(dataField.getToken());
                        assert viewAttrib != null : "Can't find matching XVA Token for DataField";
                        dataField.setViewAttribute(viewAttrib);
                    }
                    dataRecord.setFields(ve);
                }
            }
        }
    } // class ViewOdHandler

    public int getHeight() {
        return height;
    }

    /**
     * @return the lockingLevel
     */
    public LockingLevel getLockingLevel() {
        return lockingLevel;
    }

    public String getGenkeyHandler() {
        return genkeyHandler;
    }

    public SourceFileType getSourceFileType() {
        return sourceFileType;
    }
}