alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (MappingGenerator.java)

This example Glassfish source code file (MappingGenerator.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

classloader, dbexception, hashmap, integer, integer, io, iterator, jdbc, length_attribute, map, map, none_attribute, none_attribute, sql, string, string, suncmpmappings, util

The Glassfish MappingGenerator.java source code

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

/*
 * MappingGenerator.java
 *
 * Created on Aug 18, 2003
 */

package com.sun.jdo.api.persistence.mapping.ejb;

import java.util.*;
import java.sql.Types;
import java.io.IOException;

import com.sun.jdo.api.persistence.mapping.ejb.beans.*;

import com.sun.jdo.api.persistence.model.Model;
import com.sun.jdo.api.persistence.model.ModelException;
import com.sun.jdo.api.persistence.model.mapping.MappingClassElement;
import com.sun.jdo.api.persistence.model.mapping.MappingFieldElement;
import com.sun.jdo.api.persistence.model.jdo.PersistenceClassElement;
import com.sun.jdo.api.persistence.model.jdo.PersistenceFieldElement;

import com.sun.jdo.spi.persistence.utility.StringHelper;
import com.sun.jdo.spi.persistence.utility.JavaTypeHelper;

import com.sun.jdo.spi.persistence.generator.database.DatabaseGenerator;
import com.sun.jdo.spi.persistence.generator.database.MappingPolicy;

import org.netbeans.modules.dbschema.*;
import org.netbeans.modules.dbschema.jdbcimpl.SchemaElementImpl;
import org.netbeans.modules.dbschema.util.NameUtil;

import org.netbeans.modules.schema2beans.Schema2BeansException;

/*
 * This class will generate mapping classes from sun-cmp-mappings.xml
 * and dbschema if they are available in the jar, or it will generate mapping 
 * classes based on ejb-jar.xml, bean classes and policy by invoking the 
 * database generation backend.
 *
 * @author Jie Leng 
 */
public class MappingGenerator {

    // Since "_JDOState" is defined as private in IASEjbCMPEntityDescriptor,
    // redefined here for passing it in DatabaseGenerator.
    private static final String CLASS_SUFFIX = "_JDOState"; // NOI18N

    private static final String FAKE_NAME = "fakename"; // NOI18N

    private final EJBInfoHelper infoHelper;
    private final Model model;
    private final AbstractNameMapper nameMapper;
    private final ClassLoader loader;
    private final ConversionHelper ddHelper;

    /** a boolean indicating whether the jdo model and mapping model should
     * contain generated fields
     */
    private boolean skipGeneratedFields = false;

    //hold strong reference to mapping class elements 
    private List strongRefs = new ArrayList();

    /** 
     * Constructor
     * @param infoHelper an instance of an EJBInfoHelper
     * @param loader a class loader
     * @param skipGeneratedFields a boolean indicating to remove generated 
     * fields from jdo model and mapping model 
     */
    public MappingGenerator(EJBInfoHelper infoHelper, 
            ClassLoader loader, boolean skipGeneratedFields) {
        this.infoHelper = infoHelper;
        this.model = infoHelper.getModel();
        this.loader = loader;
        this.nameMapper = infoHelper.getNameMapper();
        this.ddHelper = infoHelper.createConversionHelper();
        this.skipGeneratedFields = skipGeneratedFields;
    }

    protected EJBInfoHelper getInfoHelper() {
        return infoHelper;
    }

    protected ClassLoader getClassLoader() {
        return loader;
    }

    protected AbstractNameMapper getNameMapper() {
        return nameMapper;
    }

    protected ConversionHelper getConversionHelper() {
        return ddHelper;
    }

    /**
     * Create mapping classes and schema based on database vendor name.
     * @param dbName a string for database vendor name
     * @param uniqueTableNames a Boolean to determin if use unique table names
     * during database generation
     * @param userPolicy a property object holding user overrides
     * @param inputFilesPath a directory where sun-cmp-mappings.xml is located
     * @throws IOException
     * @throws Schema2BeansException
     * @throws ModelException
     * @throws DBException
     * @throws ConversionException
     */
    public DatabaseGenerator.Results generateMappingClasses(String dbName,
            Boolean uniqueTableNames, Properties userPolicy,
            String inputFilesPath)
            throws IOException, Schema2BeansException, ModelException,
            DBException, ConversionException {

        // generate mapping classes and dbschema in memory
        SunCmpMappings sunCmpMappings = null;

        // sun-cmp-mappings.xml does not exist, use DatabaseGenerator
        // to generate sun-cmp-mappings.xml, *.dbschema

        List pcClasses = new ArrayList();
        sunCmpMappings = getPartialSunCmpMappings(pcClasses, 
                (uniqueTableNames != null)? uniqueTableNames.booleanValue() : false);

        // load real jdo model and fake mapping model in memory
        ddHelper.setEnsureValidation(false);

        // create fake schema for partial mapping
        SchemaElement fakeSchema = new SchemaElement(new SchemaElementImpl());
        fakeSchema.setName(DBIdentifier.create(FAKE_NAME));

        // add newly created fake schema to SchemaElement cache
        SchemaElement.addToCache(fakeSchema);

        // pass null as class loader in order for MappingFile to load schema
        // from cache not from disk.
        loadMappingClasses(sunCmpMappings, null);

        DatabaseGenerator.Results results = generateSchema(pcClasses,
                dbName, uniqueTableNames, userPolicy);

        SchemaElement schema = results.getSchema();
        Set mappingClasses = results.getMappingClasses();

        // remove fake schema from cache since the correct schema is generated.
        SchemaElement.removeFromCache(FAKE_NAME);

        // clean up old version of schema in SchemaElement cache
        // if there is one
        SchemaElement.removeFromCache(schema.getName().getName());

        // add newly created schema to SchemaElement cache
        SchemaElement.addToCache(schema);

        // update mapping classes
        updateMappingClasses(mappingClasses);

        // If skipGeneratedFields is set to true, the generated fields should 
        // not be kept in jdo model and mapping model. 
        // Remove generated fields from jdo model and mapping 
        // model before returning the result.
        if (skipGeneratedFields) {
            Iterator iter = mappingClasses.iterator();
            while (iter.hasNext()) {
                MappingClassElement mapClassElt = (MappingClassElement)iter.next();
                if (mapClassElt != null) {
                    String className = mapClassElt.getName();
                    String ejbName = nameMapper.getEjbNameForPersistenceClass(
                        className);

                    PersistenceClassElement pce = (PersistenceClassElement)
                            model.getPersistenceClass(className);
                    PersistenceFieldElement[] allFields = pce.getFields();
                    if (allFields != null) {
                        List generatedFieldList = new ArrayList();

                        // In order to avoid concurrentmod exception,
                        // loop through all persistence fields to put generated
                        // fields in a list, loop though the list to remove
                        // the generated fields from the model.
                        for (int i = 0; i < allFields.length; i++) { 
                            PersistenceFieldElement pfe = allFields[i];
                            if (pfe != null) { 
                                String pFieldName = pfe.getName();
                                String ejbFieldName = nameMapper.
                                    getEjbFieldForPersistenceField(className, 
                                    pFieldName);
                                if (nameMapper.isGeneratedField(ejbName, 
                                    ejbFieldName)) {
                                    generatedFieldList.add(pfe);
                                }
                            }
                        }

                        // If the field is a version field, don't remove it 
                        // from the model even though it is generated because 
                        // it is needed to hold the version column information.
                        Iterator iterator = generatedFieldList.iterator();
                        while (iterator.hasNext()) {
                            PersistenceFieldElement pfe = 
                                (PersistenceFieldElement)iterator.next();
                            MappingFieldElement mfe = mapClassElt.
                                 getField(pfe.getName());
                            if (mfe != null && (!mfe.isVersion())) {
                                model.removeFieldElement(pfe);
                                mapClassElt.removeField(mfe);
                            }
                        }
                    }
                }
            }
        }

        return results;
    }

    /**
     * load mapping classes from SunCmpMappings object
     * @param sunMapping a SunCmpMappings object representing
     * sun-cmp-mappings.xml in memory
     * @param classLoader a class loader object
     * @return a map object containing ejb names and mapping classes
     * @throws DBException
     * @throws ModelException
     * @throws ConversionException
     */
    protected Map loadMappingClasses(SunCmpMappings sunMapping, 
        ClassLoader classLoader) 
        throws DBException, ModelException, ConversionException {
        MappingFile mapFile = new MappingFile(classLoader);

        Map allMappings = mapFile.intoMappingClasses(sunMapping, ddHelper);

        updateMappingClasses(allMappings.values());

        return allMappings;
    }

    /** 
     * Clean up strong reference. It should be called by end of deployment
     * or deploytool.
     */
    public void cleanup() {
        // Remove the strong references to MappingClassElements
        // needed during deployment. The mapping class cache
        // can now be cleaned up by the garbage collector.
        strongRefs.clear();
    }

    /** 
     * Call DatabaseGenerator to generate database model and mapping model
     * @param pcClasses a list of DatabaseGenerator.GeneratorNameTuple objects 
     * @param dbVendorName the string of database name
     * @param useUniqueTableNames the string to determine use of unique table
     * names for database generation
     * @param userPolicy the property having user defined mappings between
     * class field and jdbc type
     * @return DatabaseGenerator.Results contains mapping classes and schema
     * @throws IOException
     * @throws DBException
     * @throws ModelException
     */
    private DatabaseGenerator.Results generateSchema(List pcClasses, 
            String dbName, Boolean useUniqueTableNames, 
            Properties userPolicy) 
            throws IOException, DBException, ModelException {

        MappingPolicy mappingPolicy = MappingPolicy.getMappingPolicy(dbName);
        mappingPolicy.setUserPolicy(userPolicy);

        if (useUniqueTableNames != null) {
            // It was explicitly set.
            mappingPolicy.setUniqueTableName(useUniqueTableNames.booleanValue());
        }

       return DatabaseGenerator.generate(
                model, pcClasses, mappingPolicy, 
                infoHelper.getSchemaNameToGenerate(), CLASS_SUFFIX, true);
    }

    /** 
     * Puts mapping classes into model's cache
     * @param mappingClasses a collection of mapping classes
     */ 
    private void updateMappingClasses(Collection mappingClasses) {
        Iterator iter = mappingClasses.iterator();
        while (iter.hasNext()) {
            MappingClassElement mapClassElt = (MappingClassElement)iter.next();
            //put it in the models' cache
            model.updateKeyForClass(mapClassElt, null);
            //keep a strong ref
            strongRefs.add(mapClassElt);
        }
    }

    /** 
     * Generates partial sun-cmp-mapping (contains fake table name and 
     * fake column name) for MappingFile.intoMappings()
     * @param pcClasses a list of DatabaseGenerator.NameTuple objects 
     * @param useUniqueTableNames a boolean to determine whether to use 
     * unique table names during database generation
     * @return a SunCmpMappings object
     * @throws Schema2BeansException
     */
    private SunCmpMappings getPartialSunCmpMappings(List pcClasses, 
             boolean useUniqueTableNames) throws Schema2BeansException {

       // Create a new name mapper with perisistence class name differing
        // from bean name if useUniqueTableName flag is true. 
        // So persistence class name can be used for unique table name.
        AbstractNameMapper nameMapper2 = (useUniqueTableNames) ? 
                infoHelper.createUniqueNameMapper() : nameMapper;

        SunCmpMappings mappings = null;
        mappings = new SunCmpMappings();
        SunCmpMapping mapping = new SunCmpMapping();
        mapping.setSchema(FAKE_NAME);

        Iterator iter = infoHelper.getEjbNames().iterator();
        while (iter.hasNext()) {
            String ejbName = (String)iter.next();
            String pcClass = ddHelper.getMappedClassName(ejbName);
            String hashClassName = JavaTypeHelper.getShortClassName(pcClass);

            // Make sure hash class name differs from ejb name 
            // if useUniqueTableName flag is true.
            // if useUniqueTableName flag is false, ejb name is used for 
            // table name and hash class name is ignored. 
            if (useUniqueTableNames && hashClassName.equals(ejbName)) {
                hashClassName = JavaTypeHelper.getShortClassName(
                       nameMapper2.getPersistenceClassForEjbName(ejbName));
                pcClasses.add(new DatabaseGenerator.NameTuple(
                       pcClass, ejbName, hashClassName));
            }
            else {
                pcClasses.add(new DatabaseGenerator.NameTuple(
                       pcClass, ejbName));
            }

            EntityMapping entity = new EntityMapping();
            entity.setEjbName(ejbName);
            entity.setTableName(FAKE_NAME);
            Collection fields = infoHelper.getFieldsForEjb(ejbName);
            Collection rels = infoHelper.getRelationshipsForEjb(ejbName);
            fields.removeAll(rels);
            // cmp field
            Iterator fIter = fields.iterator();
            while (fIter.hasNext()) {
                String fieldName = (String)fIter.next();
                CmpFieldMapping cmpField = new CmpFieldMapping();
                cmpField.setFieldName(fieldName);
                cmpField.addColumnName(FAKE_NAME);
                entity.addCmpFieldMapping(cmpField);
            } 
            // cmr field
            fIter = rels.iterator();
            while (fIter.hasNext()) {
                String fieldName = (String)fIter.next();
                CmrFieldMapping cmrField = new CmrFieldMapping();
                cmrField.setCmrFieldName(fieldName);
                ColumnPair columnPair = new ColumnPair();
                columnPair.addColumnName(FAKE_NAME);
                columnPair.addColumnName(FAKE_NAME);
                cmrField.addColumnPair(columnPair);
                entity.addCmrFieldMapping(cmrField);
            }
            mapping.addEntityMapping(entity);
        }

        mappings.addSunCmpMapping(mapping);

        return mappings;
    }

    /** 
     * Returns <code>true if the specified propertyValue represents
     * a defined value, <code>false otherwise.  This implementation 
     * returns <code>true if the value is not empty, but subclasses
     * may override this method to compare to a constant which represents an
     * undefined value.
     * @param propertyValue the value to be tested for defined
     * @return <code>true if the specified propertyValue represents
     * a defined value, <code>false otherwise
     */
    protected boolean isPropertyDefined(String propertyValue) {
        return !StringHelper.isEmpty(propertyValue);
    }

    /** 
     * Update column in the SchemaElement with jdbc type and its length, 
     * scale and precision.
     * @param column a ColumnElement to be updated
     * @param jdbcType jdbc type from java.sql.Types
     * @param length an Integer for length or <code>null 
     * if it does not apply
     * @param scale an Integer for scale or <code>null 
     * if it does not apply
     * @param precision an Integer for precision or <code>null 
     * if it does not apply
     */
    public static void updateColumn(ColumnElement column, int jdbcType, 
            Integer length, Integer scale, Integer precision)
            throws DBException {

        column.setType(jdbcType);
        column.setLength(length);
        column.setScale(scale);
        column.setPrecision(precision);
    }

    /**
     * This method updates properties which stores user override policy.
     * @param prop the property for user override
     * @param className a string for bean class
     * @param fieldName a string for field
     * @param jdbcType jdbc type from java.sql.Types
     * @param length an Integer for length or <code>null
     * if it does not apply
     * @param scale an Integer for scale or <code>null
     * if it does not apply
     * @param precision an Integer for precision or <code>null
     * if it does not apply
     */
    public static void updateProperties(Properties prop, String className, 
            String fieldName, int jdbcType, Integer length, Integer scale, 
            Integer precision) {

        prop.setProperty(
                MappingPolicy.getOverrideForType(className, fieldName),
                MappingPolicy.getJdbcTypeName(jdbcType));

        updateProperty(prop, MappingPolicy.getOverrideForLength(
                className, fieldName), length);

        updateProperty(prop, MappingPolicy.getOverrideForScale(
                className, fieldName), scale);

        updateProperty(prop, MappingPolicy.getOverrideForPrecision(
                className, fieldName), precision);
    }

    /**
     * This method updates property. If the value is not <code>null,
     * update the property. If the value is <code>null, 
     * remove the property.
     * @param prop a property object which needs to be updated
     * @param key a key for the property
     * @param value a value for the propety
     */
    private static void updateProperty(Properties prop, String key, 
            Integer value) {
        if (value != null) {
            prop.setProperty(key, value.toString());
        }
        else {
           prop.remove(key);
        }
    }

    /**
     * The contents of this class will eventually be added to SQLTypeUtil 
     * in dbmodel. It is an util class which provides methods for jdbc type 
     * compatible and jdbc attribute.
     */
    public static class SQLTypeUtil {

        private static final Map characterMap = new HashMap();
        private static final Map numericMap = new HashMap();
        private static final Map blobMap = new HashMap();
        private static final Map timeMap = new HashMap();
        
        private static final String NONE_ATTRIBUTE = "none";
        private static final String LENGTH_ATTRIBUTE = "length";
        private static final String SCALE_ATTRIBUTE = "scale";
        private static final String SCALE_PRECISION_ATTRIBUTE = "scale-precision";

        static {
            characterMap.put(new Integer(Types.CHAR), LENGTH_ATTRIBUTE);
            characterMap.put(new Integer(Types.VARCHAR), LENGTH_ATTRIBUTE);
            characterMap.put(new Integer(Types.CLOB), LENGTH_ATTRIBUTE);

            numericMap.put(new Integer(Types.BIT), NONE_ATTRIBUTE);
            numericMap.put(new Integer(Types.TINYINT), NONE_ATTRIBUTE);
            numericMap.put(new Integer(Types.SMALLINT), NONE_ATTRIBUTE);
            numericMap.put(new Integer(Types.BIGINT), NONE_ATTRIBUTE);
            numericMap.put(new Integer(Types.INTEGER), NONE_ATTRIBUTE);
            numericMap.put(new Integer(Types.DOUBLE), NONE_ATTRIBUTE);
            numericMap.put(new Integer(Types.DECIMAL), SCALE_PRECISION_ATTRIBUTE);
            numericMap.put(new Integer(Types.REAL), NONE_ATTRIBUTE);

            blobMap.put(new Integer(Types.BLOB), LENGTH_ATTRIBUTE);

            timeMap.put(new Integer(Types.DATE), NONE_ATTRIBUTE);
            timeMap.put(new Integer(Types.TIME), NONE_ATTRIBUTE);
            timeMap.put(new Integer(Types.TIMESTAMP), NONE_ATTRIBUTE);
        }

        /** Returns if the given data type is numeric type or not.
         * @param jdbcType the type from java.sql.Types
         * @return <code>true if the given type is numeric type; 
         * <code>false otherwise
         */
        public static boolean isNumeric (int jdbcType) {
            return checkType(jdbcType, numericMap);
        }

        /** Returns if the given data type is character type or not.
         * @param jdbcType the type from java.sql.Types
         * @return <code>true if the given type is character type; 
         * <code>false otherwise
         */
        public static boolean isCharacter (int jdbcType) {
            return checkType(jdbcType, characterMap);
        }

        /** Returns if a given data type is blob type or not.
         * @param jdbcType the type from java.sql.Types
         * @return <code>true if the give type is blob type; 
         * <code>false otherwise
         */
        public static boolean isBlob (int jdbcType) {
            return checkType(jdbcType, blobMap);
        }

        /** Returns if a given data type is time type or not.
         * @param jdbcType the type from java.sql.Types
         * @return <code>true if the give type is time type; 
         * <code>false otherwise
         */
        public static boolean isTime (int jdbcType) {
            return checkType(jdbcType, timeMap);
        }

        private static boolean checkType(int jdbcType, Map jdbcTypes) {
            return jdbcTypes.containsKey(new Integer(jdbcType));
        }

        /** Returns a collection of compatible jdbc types.
         * @param jdbcType the type from java.sql.Types 
         * @return a collection of compatible jdbc types 
         */
        public static Collection getCompatibleTypes(int jdbcType) {
            if (isNumeric(jdbcType)) {
                return numericMap.keySet();
            }
            else if (isCharacter(jdbcType)) {
                return characterMap.keySet();
            }
            else if (isBlob(jdbcType)) {
                return blobMap.keySet();
            }
            else if (isTime(jdbcType)) {
                return timeMap.keySet();
            }
            return null;
        }

        /**
         * This method returns true if the jdbc type has scale. 
         * @param jdbcType a jdbc type from java.sql.Types
         * @return <code>true if the type has scale;
         * <code>false otherwise 
         */
        public static boolean hasScale(int jdbcType) {
            if (getAttribute(jdbcType).equals(SCALE_ATTRIBUTE)
                    || getAttribute(jdbcType).equals(SCALE_PRECISION_ATTRIBUTE))
                return true;
            return false;
        }

        /**
         * This method returns true if the jdbc type has precision. 
         * If the jdbc type has the precision, it means it also has scale. 
         * @param jdbcType a jdbc type from java.sql.Types
         * @return <code>true if the type has precision; 
         * <code>false otherwise 
         */
        public static boolean hasPrecision(int jdbcType) {
            if (getAttribute(jdbcType).equals(SCALE_PRECISION_ATTRIBUTE))
                return true;
            return false;
        }

        /**
         * This method returns true if the jdbc type has length
         * @param jdbcType a jdbc type from java.sql.Types
         * @return <code>true if the type has length;
         * <code>false otherwise
         */
        public static boolean hasLength(int jdbcType) {
            if (getAttribute(jdbcType).equals(LENGTH_ATTRIBUTE))
                return true;
            return false;
        }

        private static String getAttribute(int jdbcType) {
            if (isNumeric(jdbcType)) {
                return (String)numericMap.get(new Integer(jdbcType));
            }
            else if (isCharacter(jdbcType)) {
                return (String)characterMap.get(new Integer(jdbcType));
            }
            else if (isBlob(jdbcType)) {
                return (String)blobMap.get(new Integer(jdbcType));
            }
            else if (isTime(jdbcType)) {
                return (String)timeMap.get(new Integer(jdbcType));
            }
            return NONE_ATTRIBUTE;
        }
    }
}

Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish MappingGenerator.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.