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

org.openmdx.application.dataprovider.cci.JmiHelper Maven / Gradle / Ivy

There is a newer version: 2.18.10
Show newest version
/*
 * ====================================================================
 * Project:     openMDX/Portal, http://www.openmdx.org/
 * Description: JmiHelper class
 * Owner:       OMEX AG, Switzerland, http://www.omex.ch
 * ====================================================================
 *
 * This software is published under the BSD license as listed below.
 * 
 * Copyright (c) 2004-2013, OMEX AG, Switzerland
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 * 
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 * 
 * * Neither the name of the openMDX team nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * ------------------
 * 
 * This product includes software developed by other organizations as
 * listed in the NOTICE file.
 */
package org.openmdx.application.dataprovider.cci;

import java.net.URI;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;

import javax.jdo.PersistenceManager;
import javax.jmi.reflect.RefObject;
import javax.resource.cci.MappedRecord;
import javax.xml.datatype.Duration;
import javax.xml.datatype.XMLGregorianCalendar;

import org.openmdx.base.accessor.cci.SystemAttributes;
import org.openmdx.base.accessor.jmi.cci.RefPackage_1_0;
import org.openmdx.base.collection.MarshallingList;
import org.openmdx.base.collection.MarshallingSet;
import org.openmdx.base.collection.MarshallingSparseArray;
import org.openmdx.base.exception.ServiceException;
import org.openmdx.base.marshalling.Marshaller;
import org.openmdx.base.mof.cci.ModelElement_1_0;
import org.openmdx.base.mof.cci.ModelHelper;
import org.openmdx.base.mof.cci.Model_1_0;
import org.openmdx.base.mof.cci.Multiplicity;
import org.openmdx.base.mof.cci.PrimitiveTypes;
import org.openmdx.base.naming.Path;
import org.openmdx.base.query.LenientPathComparator;
import org.openmdx.base.rest.spi.Facades;
import org.openmdx.base.rest.spi.Object_2Facade;
import org.openmdx.kernel.exception.BasicException;
import org.openmdx.kernel.jdo.ReducedJDOHelper;
import org.w3c.cci2.SparseArray;
import org.w3c.spi2.Datatypes;

//---------------------------------------------------------------------------
@SuppressWarnings("unchecked")
public class JmiHelper {

    /**
     * The default set of ignorable features
     */
    private static final Collection DEFAULT_SET_OF_IGNORABLE_FEATURES = Arrays.asList(
        SystemAttributes.OBJECT_CLASS
    );
    
    //-------------------------------------------------------------------------
    static class ToRefObjectValueMarshaller implements Marshaller {

        ToRefObjectValueMarshaller(
            Map objectCache,
            PersistenceManager pm,
            Model_1_0 model,
            String typeName
        ) throws ServiceException {
            this.objectCache = objectCache;
            this.pm = pm;
            this.model = model;
            this.typeName = typeName;
        }

        public Object marshal(
            Object source
        ) throws ServiceException {
            if(this.model.isClassType(this.typeName)) {
                if(source == null) {
                    return null;
                } else if(source instanceof Path) {
                    if(this.objectCache.containsKey(source)) {
                        Object object = this.objectCache.get(source);
                        return ReducedJDOHelper.getPersistenceManager(object) == this.pm ? object : this.pm.getObjectById(
                            ReducedJDOHelper.getTransactionalObjectId(object)
                        );
                    } else {
                        return this.pm.getObjectById(source);
                    }
                } else {
                    return ReducedJDOHelper.getPersistenceManager(source) == this.pm ? source : this.pm.getObjectById(
                        ReducedJDOHelper.getObjectId(source)
                    );
                }
            } else if(PrimitiveTypes.DATETIME.equals(this.typeName)) {
                return source instanceof Date ? source : Datatypes.create(
                    Date.class, 
                    (String)source
                );
            } else if(PrimitiveTypes.DATE.equals(this.typeName)) {                
                return source instanceof XMLGregorianCalendar ? source : Datatypes.create(
                    XMLGregorianCalendar.class, 
                    (String)source
                );
            } else if(PrimitiveTypes.DURATION.equals(this.typeName)) {                
                return source instanceof Duration ? source : Datatypes.create(
                    Duration.class, 
                    (String)source
                );
            } else if(PrimitiveTypes.ANYURI.equals(this.typeName)) {                
                return source instanceof URI ? source : Datatypes.create(
                    URI.class, 
                    (String)source
                );
            } else {
                return source;
            }            
        }

        public Object unmarshal(
            Object source
        ) throws ServiceException {
            throw new UnsupportedOperationException();
        }

        private final Map objectCache;    
        private final PersistenceManager pm;
        private final Model_1_0 model;
        private final String typeName;
    }

    //-------------------------------------------------------------------------
    private static boolean areEqual(
        Object v1,
        Object v2
    ) {
        return
            v1 == null ? v2 == null :
            v2 == null ? false :
            LenientPathComparator.isComparable(v1) ? LenientPathComparator.getInstance().compare(v1, v2) == 0 :
            v1.equals(v2);
    }

    //---------------------------------------------------------------------------
    @SuppressWarnings("rawtypes")
    private static void setRefObjectValues(
        Object sourceValues,
        Marshaller marshaller,
        Object targetValues,
        ModelElement_1_0 featureDef, 
        boolean compareWithBeforeImage
    ) throws ServiceException {
        if(targetValues instanceof List) {
            if(!compareWithBeforeImage || !areEqual(targetValues, new MarshallingList(marshaller, (List)sourceValues))) {
                ((List)targetValues).clear();
                for(
                    ListIterator j = ((List)sourceValues).listIterator();
                    j.hasNext();
                ) {
                    if(j.nextIndex() < ((List)targetValues).size()) {
                        ((List)targetValues).set(
                            j.nextIndex(),
                            marshaller.marshal(j.next())
                        );
                    }
                    else {
                        ((List)targetValues).add(
                            j.nextIndex(),
                            marshaller.marshal(j.next())
                        );
                    }
                }
            }
        }
        else if(targetValues instanceof Set) {
            if(!compareWithBeforeImage || !areEqual(targetValues, new MarshallingSet(marshaller, (Collection)sourceValues))) {
                ((Set)targetValues).clear();
                for(
                    Iterator j = ((Collection)sourceValues).iterator();
                    j.hasNext();
                ) {
                    ((Set)targetValues).add(
                        marshaller.marshal(j.next())
                    );
                }
            }
        }
        else if(targetValues instanceof SparseArray) {
            if(!compareWithBeforeImage || !areEqual(new MarshallingSparseArray(marshaller, (SparseArray)sourceValues), targetValues)) {
                ((SparseArray)targetValues).clear();
                for(
                    ListIterator j = ((SparseArray)sourceValues).populationIterator();
                    j.hasNext();
                ) {
                    ((SparseArray)targetValues).put(
                        Integer.valueOf(j.nextIndex()),
                        marshaller.marshal(j.next())
                    );
                }
            }
        }
        else {
            throw new ServiceException(
                BasicException.Code.DEFAULT_DOMAIN,
                BasicException.Code.ASSERTION_FAILURE, 
                "Unsupported collection type",
                new BasicException.Parameter("collection.type", targetValues.getClass().getName())
            );
        }
    }

    //------------------------------------------------------------------------
    public static void toRefObject(
        MappedRecord source,
        RefObject target,
        Map objectCache,
        Collection ignorableFeatures, 
        boolean compareWithBeforeImage
    ) throws ServiceException {
        PersistenceManager pm = ReducedJDOHelper.getPersistenceManager(target);
        String typeName = Object_2Facade.getObjectClass(source);
        Object_2Facade facade = Facades.asObject(source);
        Model_1_0 model = ((RefPackage_1_0)target.refImmediatePackage()).refModel();
        ModelElement_1_0 classDef = model.getElement(typeName);
        Features: for(String featureName: (Set)facade.getValue().keySet()) {
            if((ignorableFeatures == null ? DEFAULT_SET_OF_IGNORABLE_FEATURES : ignorableFeatures).contains(featureName)) {
                continue Features;
            }
            ModelElement_1_0 featureDef = model.getFeatureDef(
                classDef,
                featureName,
                true
            ); 
            if(featureDef == null) {
                throw new ServiceException(
                    BasicException.Code.DEFAULT_DOMAIN,
                    BasicException.Code.BAD_MEMBER_NAME, 
                    "attribute not found in class",
                    new BasicException.Parameter("class", classDef),
                    new BasicException.Parameter("attribute name", featureName)
                );
            }
            if(Boolean.TRUE.equals(featureDef.isDerived())) {
                continue Features;
            }
            ModelElement_1_0 featureType = model.getElementType(
                featureDef
            );
            Marshaller marshaller = new ToRefObjectValueMarshaller(
                objectCache, 
                pm, 
                model,
                featureType.getQualifiedName()
            );
            //
            // Store the attribute value to target according to the attribute's multiplicity
            // 
            Multiplicity multiplicity = ModelHelper.getMultiplicity(featureDef);
			switch(multiplicity){
	            case OPTIONAL: {
	                Object sourceValue = facade.attributeValue(featureName);                
	                if(compareWithBeforeImage){
	                    Object targetValue = target.refGetValue(featureName);
	                    if(!areEqual(targetValue, sourceValue)) {
	                        target.refSetValue(
	                            featureName,
	                            marshaller.marshal(sourceValue)
	                        );
	                    }
	                } else {
	                    target.refSetValue(
	                        featureName,
	                        marshaller.marshal(sourceValue)
	                    );
	                }
	            } break;
	            case SINGLE_VALUE: {
	                Object sourceValue = facade.attributeValue(featureName);                
	                //
	                // before image should not be retrieved in case of primitive types!
	                //
	                target.refSetValue(
	                    featureName,
	                    marshaller.marshal(sourceValue)
	                );
	            } break;
	            case LIST: case SET: case SPARSEARRAY: {
	                Object sourceValues = facade.attributeValues(featureName);                
	                setRefObjectValues(
	                    sourceValues,
	                    marshaller,
	                    target.refGetValue(featureName),
	                    featureDef, 
	                    compareWithBeforeImage
	                );
	            } break;
				default:
	                throw new ServiceException(
	                    BasicException.Code.DEFAULT_DOMAIN,
	                    BasicException.Code.NOT_SUPPORTED, 
	                    "Unsupported multiplicity. Supported are 0..1, 1..1, list, set, sparsearray and in case of references 0..n",
	                    new BasicException.Parameter("multiplicity", multiplicity),
	                    new BasicException.Parameter("attribute name", featureName)
	                );        
            }
        }
    }

}

//--- End of File -----------------------------------------------------------




© 2015 - 2024 Weber Informatics LLC | Privacy Policy