/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.eclipse.persistence.tools.workbench.mappingsmodel.MWModel; import org.eclipse.persistence.tools.workbench.mappingsmodel.ProblemConstants; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.relational.MWTableDescriptorLockingPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.xml.MWEisDescriptorLockingPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.descriptor.xml.MWOXDescriptorLockingPolicy; import org.eclipse.persistence.tools.workbench.mappingsmodel.mapping.MWMapping; import org.eclipse.persistence.tools.workbench.utility.node.Node; import org.eclipse.persistence.descriptors.CMPPolicy; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.descriptors.DescriptorEvent; import org.eclipse.persistence.descriptors.InheritancePolicy; import org.eclipse.persistence.descriptors.PessimisticLockingPolicy; import org.eclipse.persistence.mappings.converters.ObjectTypeConverter; import org.eclipse.persistence.oxm.XMLDescriptor; import org.eclipse.persistence.oxm.mappings.XMLDirectMapping; import org.eclipse.persistence.queries.ObjectLevelReadQuery; public abstract class MWDescriptorLockingPolicy extends MWModel implements MWLockingPolicy { private volatile String lockingType; private volatile String optimisticVersionLockingType; public final static String OPTIMISTIC_VERSION_LOCKING_TYPE_PROPERTY = "optimisticVersionLockingType"; // version optimistic locking public final static String OPTIMISTIC_VERSION_VERSION = "Version Locking"; public final static String OPTIMISTIC_VERSION_TIMESTAMP = "Timestamp Locking"; public final static String DEFAULT_OPTIMISTIC_VERSION_LOCKING_TYPE = OPTIMISTIC_VERSION_VERSION; private volatile boolean storeInCache; private volatile boolean waitForLock; public final static String WAIT_FOR_LOCK_PROPERTY = "waitForLock"; private volatile String retrieveTimeFrom; public final static String RETRIEVE_TIME_FROM_PROPERTY = "retrieveTimeFrom"; public final static String SERVER_TIME = "Server"; public final static String LOCAL_TIME = "Local"; // ********** static methods ********** public static XMLDescriptor buildDescriptor() { XMLDescriptor descriptor = new XMLDescriptor(); descriptor.getInheritancePolicy(); descriptor.setJavaClass(MWDescriptorLockingPolicy.class); ObjectTypeConverter lockingTypeConverter = new ObjectTypeConverter(); lockingTypeConverter.addConversionValue( NO_LOCKING, NO_LOCKING); lockingTypeConverter.addConversionValue( OPTIMISTIC_LOCKING, OPTIMISTIC_LOCKING); lockingTypeConverter.addConversionValue( PESSIMISTIC_LOCKING, PESSIMISTIC_LOCKING); XMLDirectMapping lockingTypeMapping = new XMLDirectMapping(); lockingTypeMapping.setAttributeName("lockingType"); lockingTypeMapping.setXPath("locking-type/text()"); lockingTypeMapping.setNullValue(NO_LOCKING); lockingTypeMapping.setConverter(lockingTypeConverter); descriptor.addMapping(lockingTypeMapping); ObjectTypeConverter versionLockingTypeConverter = new ObjectTypeConverter(); versionLockingTypeConverter.addConversionValue( MWDescriptorLockingPolicy.OPTIMISTIC_VERSION_VERSION, MWDescriptorLockingPolicy.OPTIMISTIC_VERSION_VERSION); versionLockingTypeConverter.addConversionValue( MWDescriptorLockingPolicy.OPTIMISTIC_VERSION_TIMESTAMP, MWDescriptorLockingPolicy.OPTIMISTIC_VERSION_TIMESTAMP); XMLDirectMapping versionLockingTypeMapping = new XMLDirectMapping(); versionLockingTypeMapping.setAttributeName("optimisticVersionLockingType"); versionLockingTypeMapping.setXPath("version-locking-type/text()"); versionLockingTypeMapping.setConverter(versionLockingTypeConverter); descriptor.addMapping(versionLockingTypeMapping); ObjectTypeConverter retrieveTimeFromTypeConverter = new ObjectTypeConverter(); retrieveTimeFromTypeConverter.addConversionValue( MWDescriptorLockingPolicy.SERVER_TIME, MWDescriptorLockingPolicy.SERVER_TIME); retrieveTimeFromTypeConverter.addConversionValue( MWDescriptorLockingPolicy.LOCAL_TIME, MWDescriptorLockingPolicy.LOCAL_TIME); XMLDirectMapping retrieveTimeFromMapping = new XMLDirectMapping(); retrieveTimeFromMapping.setAttributeName("retrieveTimeFrom"); retrieveTimeFromMapping.setXPath("retrieve-time-from/text()"); retrieveTimeFromMapping.setConverter(retrieveTimeFromTypeConverter); retrieveTimeFromMapping.setNullValue(MWDescriptorLockingPolicy.SERVER_TIME); descriptor.addMapping(retrieveTimeFromMapping); ((XMLDirectMapping) descriptor.addDirectMapping("storeInCache", "store-in-cache/text()")).setNullValue(Boolean.TRUE); ((XMLDirectMapping) descriptor.addDirectMapping("waitForLock", "wait-for-lock/text()")).setNullValue(Boolean.TRUE); InheritancePolicy ip = (InheritancePolicy)descriptor.getInheritancePolicy(); ip.setClassIndicatorFieldName("@type"); ip.addClassIndicator(MWTableDescriptorLockingPolicy.class, "relational"); ip.addClassIndicator(MWEisDescriptorLockingPolicy.class, "eis"); ip.addClassIndicator(MWOXDescriptorLockingPolicy.class, "ox"); return descriptor; } protected MWDescriptorLockingPolicy() { // for TopLink use only super(); } public MWDescriptorLockingPolicy(MWTransactionalPolicy descriptor) { super(descriptor); } protected void initialize(Node parent) { super.initialize(parent); this.lockingType = DEFAULT_LOCKING_TYPE; this.storeInCache = true; this.waitForLock = true; this.retrieveTimeFrom = SERVER_TIME; } // ******** accessors ********* public String getLockingType() { return this.lockingType; } public void setLockingType(String newLockingType) { String oldLockingType = this.lockingType; this.lockingType = newLockingType; firePropertyChanged(LOCKING_TYPE_PROPERTY, oldLockingType, newLockingType); if (attributeValueHasChanged(oldLockingType, this.lockingType)) { if (newLockingType != OPTIMISTIC_LOCKING) { setOptimisticVersionLockingType(null); } else { setOptimisticVersionLockingType(DEFAULT_OPTIMISTIC_VERSION_LOCKING_TYPE); } } } public boolean shouldStoreVersionInCache() { return this.storeInCache; } public void setStoreInCache(boolean newStoreInCache) { boolean oldStoreInCache = this.storeInCache; this.storeInCache = newStoreInCache; firePropertyChanged(STORE_IN_CACHE_PROPERTY, oldStoreInCache, newStoreInCache); } public boolean shouldWaitForLock() { return this.waitForLock; } public void setWaitForLock(boolean newValue) { boolean oldWaitForLock = this.waitForLock; this.waitForLock = newValue; firePropertyChanged(WAIT_FOR_LOCK_PROPERTY, oldWaitForLock, this.waitForLock); } public MWMappingDescriptor getOwningDescriptor() { return (MWMappingDescriptor) ((MWTransactionalPolicy) this.getParent()).getParent(); } public void toString(StringBuffer sb) { sb.append(getLockingType()); } public void adjustRuntimeDescriptor(ClassDescriptor runtimeDescriptor) { if (getLockingType() == PESSIMISTIC_LOCKING) { if(runtimeDescriptor.getCMPPolicy() == null) { runtimeDescriptor.setCMPPolicy(new CMPPolicy()); } runtimeDescriptor.getCMPPolicy().setPessimisticLockingPolicy(new PessimisticLockingPolicy()); if (shouldWaitForLock()) { runtimeDescriptor.getCMPPolicy().getPessimisticLockingPolicy().setLockingMode(ObjectLevelReadQuery.LOCK); } else { runtimeDescriptor.getCMPPolicy().getPessimisticLockingPolicy().setLockingMode(ObjectLevelReadQuery.LOCK_NOWAIT); } } } protected void addProblemsTo(List problems) { super.addProblemsTo(problems); this.checkLockFieldSpecifiedForLockingPolicy(problems); this.checkWriteLockFieldWritable(problems); } protected abstract void checkLockFieldSpecifiedForLockingPolicy(List newProblems); protected void checkWriteLockFieldWritable(List newProblems) { if (this.getLockingType() != OPTIMISTIC_LOCKING) { return; } if (this.shouldStoreVersionInCache()) { return; } Collection writtenFields = new ArrayList(); for (Iterator mappings = this.getOwningDescriptor().mappingsIncludingInherited(); mappings.hasNext(); ) { MWMapping mapping = (MWMapping) mappings.next(); if (mapping.isReadOnly()) { continue; // skip to next mapping } mapping.addWrittenFieldsTo(writtenFields); for (Iterator fields = writtenFields.iterator(); fields.hasNext(); ) { // find out if there is a writable mapping to the write // lock field, if so this test passes if (fields.next() == this.getVersionLockField()) { return; } } writtenFields.clear(); } // a writable mapping was not found newProblems.add(this.buildProblem(ProblemConstants.DESCRIPTOR_LOCKING_FIELD_WRITEABLE)); } public String getOptimisticVersionLockingType() { return this.optimisticVersionLockingType; } public void setOptimisticVersionLockingType(String versionType) { String oldValue = this.optimisticVersionLockingType; this.optimisticVersionLockingType = versionType; firePropertyChanged(OPTIMISTIC_VERSION_LOCKING_TYPE_PROPERTY, oldValue, this.optimisticVersionLockingType); } public String getRetrieveTimeFrom() { return this.retrieveTimeFrom; } public boolean usesServerTime() { return this.retrieveTimeFrom == SERVER_TIME; } public boolean usesLocalTime() { return this.retrieveTimeFrom == LOCAL_TIME; } public void setRetrieveTimeFrom(String newValue) { Object oldValue = this.retrieveTimeFrom; retrieveTimeFrom = newValue; firePropertyChanged(RETRIEVE_TIME_FROM_PROPERTY, oldValue, this.retrieveTimeFrom); } }