/*******************************************************************************
* 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.scplugin.model.adapter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.prefs.Preferences;
import org.eclipse.persistence.tools.workbench.scplugin.model.SCModel;
import org.eclipse.persistence.tools.workbench.scplugin.model.meta.ClassRepository;
import org.eclipse.persistence.tools.workbench.utility.ClassTools;
import org.eclipse.persistence.tools.workbench.utility.CollectionTools;
import org.eclipse.persistence.tools.workbench.utility.iterators.ArrayIterator;
import org.eclipse.persistence.tools.workbench.utility.iterators.TransformationIterator;
/**
* Base class for all Session Configuration adapters.
* This family of class allows the Session Configuration model classes
* to be integrated with the Mapping Workbench UI framework.
*
* Typically, subclasses should considering implementing the following methods:
* the constructor for creating a new config object.
* the constructor for adapting an existing config object.
* #addChildrenTo(List children)
* #buildModel()
* #initialize()
* #initialize( Object config)
* #initializeDefaults()
* #initializeFromModel( Object config)
* #postInitializationFromModel()
* #preSaving
* #postSaving
* #toString( StringBuffer sb)
*
* @author Tran Le
*/
public abstract class SCAdapter extends SCModel {
private final static String adapterPackageName = ClassTools.packageNameFor( SCAdapter.class) + ".";
private final static String adapterClassSuffix = "Adapter";
public final static String modelClassSuffix = "Config";
private volatile Object config;
private volatile boolean configClean; // false when config element containts users data.
private volatile boolean configRequired; // true when config element is mandated in the schema.
/**
* Constructor for SCAdapter.
*/
SCAdapter() {
super();
}
/**
* Creates a new SCAdapter and builds a new config object.
*/
protected SCAdapter( SCAdapter parent) {
super( parent);
this.initialize( buildModel());
this.initializeDefaults();
this.setConfigClean( true);
}
/**
* Creates a SCAdapter for adapting the specified config object.
*/
SCAdapter( SCAdapter parent, Object configObject) {
super( parent);
this.initializeFromModel( configObject);
this.setConfigClean( false); // contains user's config
}
/**
* Internal: Factory method for building this model.
*/
protected abstract Object buildModel();
/**
* Returns the Preferences node used by the SC.
*/
Preferences preferences() {
return ((SCAdapter) getParent()).preferences();
}
/**
* Returns the <code>ClassRepository</code> that should be used by the
* sessions.xml.
*
* @return The repository for classpath entries and classes
*/
public ClassRepository getClassRepository()
{
return ((SCAdapter) getParent()).getClassRepository();
}
/**
* Internal: Returns the adapter's Config Object.
*/
protected Object getModel() {
return this.config;
}
/**
* Returns this sessions.xml version.
* // true when config is mandated in the schema.
*/
protected final String getConfigFileVersion() {
if( this.getParent() == null) {
return (( TopLinkSessionsAdapter)this).getVersion();
}
return (( SCAdapter)this.getParent()).getConfigFileVersion();
}
/**
* Returns true if sessions.xml version is previous to 10g.
* For EL added the version > 3 clause since the version number has reset.
* When EL Workbench surpasses 3.0 this will need to be revisited, but perhaps we
* won't be supporting opening older TL sessions files and this method can be removed.
*/
protected final boolean configVersionIsPre10g() {
String versionString = this.getConfigFileVersion();
int version = 0;
for( int i = 0; i < versionString.length(); i++) {
char c = versionString.charAt( i);
if( Character.isDigit( c))
version *= 10;
else
break;
version += Character.digit( c, 10);
}
return ( version > 3 && version < 10);
}
/**
* Returns True when this config is clean and is not a mandated element in the schema.
*/
public boolean hasNoConfigToSave() {
return this.isACleanConfig() && !isARequiredConfig();
}
/**
* Returns True when this config element has not been setup.
*/
protected boolean isACleanConfig() {
return this.configClean;
}
/**
* Returns True when this config element is mandated in the schema.
*/
public boolean isARequiredConfig() {
return this.configRequired;
}
/**
* Sets the adapter's Config Object.
*/
private final void setModel( Object config) {
this.config = config;
}
/**
* Sets the configClean flag.
* Allows at saving, to ignore this config if it does not contains user data.
* True when config element has not been setup.
*/
protected final void setConfigClean( boolean clean) {
this.configClean = clean;
}
/**
* Sets the configRequired flag.
* True when config element is mandated in the schema.
*/
protected final void setConfigRequired( boolean required) {
this.configRequired = required;
}
/**
* Mark the object and all its descendants as clean.
* Typically used after a config model and its adapter
* has been created and initialized.
*/
protected void markEntireConfigurationClean() {
this.setConfigClean( true);
for( Iterator i = children(); i.hasNext(); ) {
(( SCAdapter)i.next()).setConfigClean( true);
}
}
/**
* Mark the object and its parent as dirty branches
*/
public void markBranchDirty() {
super.markBranchDirty();
this.setConfigClean( false);
}
/**
* Pre Saving: Prepares this instance config model and
* its children config model for saving.
*/
protected void preSaving() {
return;
}
/**
* Post Saving: Re-intilizes this instance config model and
* its children config model after saving.
*/
protected void postSaving() {
return;
}
/**
* Builds children adapters for the given modelObjects collection.
* and returns a collection of resulting adapters.
*
* @param modelObjects
*/
protected Collection adaptAll( Collection configObjects) {
Collection result = new ArrayList( configObjects.size());
for( Iterator i = configObjects.iterator(); i.hasNext(); ) {
result.add( this.adapt( i.next()));
}
return result;
}
/**
* Builds this child adapter for the given modelObject.
*
* @param modelObject
*/
protected SCAdapter adapt( Object configObject) {
if( configObject == null) return null;
Constructor adapterConstructor = adapterConstructorFor( configObject);
return SCAdapter.buildsAdapterWith( adapterConstructor, new Object[] { this, configObject });
}
/**
* From a collection of adapters extract the modelObjects.
*/
protected Collection modelObjectsFrom( Collection adapters) {
Iterator iterator = new TransformationIterator( adapters.iterator()) {
protected Object transform( Object next) {
return (( SCAdapter)next).getModel();
}
};
return CollectionTools.collection( iterator);
}
/**
* From a collection find the adapter for the specified modelObject.
*/
protected SCAdapter findAdapterFor( Object modelObject, Iterator iterator) {
for( Iterator i = iterator; i.hasNext(); ){
SCAdapter adapter = ( SCAdapter)i.next();
if( adapter.getModel() == modelObject)
return adapter;
}
return null;
}
/**
* Returns the two-parameter constructor of the given adapterClass
* (i.e. ASCAdapter( SCAdapter parent, Object configObject)).
* When the adapterClass is an abstract class, finds the appropriate concrete adapter
* with the method #adapterClassFor( Class);
*
* @param configObject
*/
private final Constructor adapterConstructorFor( Object configObject) {
Class adapterClass = adapterClassFor( configObject);
Class configClass = configObject.getClass();
return adapterConstructorFor( configClass, adapterClass, 2);
}
/**
* Returns the one-parameter constructor of the given adapterClass
*/
final static Constructor adapterConstructor( Class adapterClass) {
Object configObject = null;
try {
configObject = (( SCAdapter)adapterClass.newInstance()).buildModel(); // required zero-parameter constructor
}
catch( InstantiationException ie) {
throw new RuntimeException("Instantiation Exception When Instantiating " + adapterClass.getName(), ie);
}
catch( IllegalAccessException iae) {
throw new RuntimeException("Illegal Access Exception When Instantiating " + adapterClass.getName(), iae);
}
return adapterConstructorFor( configObject.getClass(), adapterClass, 1);
}
/**
* Returns the appropriate adapter constructor based the given numberOfConstructorParameter
*/
private final static Constructor adapterConstructorFor( Class configClass, Class adapterClass, int numberOfConstructorParameter) {
for( Iterator i = new ArrayIterator( adapterClass.getDeclaredConstructors()); i.hasNext(); ) {
Constructor adapterConstructor = ( Constructor)i.next();
Class[] parameters = adapterConstructor.getParameterTypes();
if( parameters.length == numberOfConstructorParameter) {
if(( parameters.length == 2) // ( SCAdapter parent, Object configObject)
&& ( parameters[ 0].isAssignableFrom( SCAdapter.class))
&& ( parameters[ 1].isAssignableFrom( configClass)))
return adapterConstructor;
else if(( parameters.length == 1) // ( SCAdapter parent)
&& ( parameters[ 0].isAssignableFrom( SCAdapter.class)))
return adapterConstructor;
else if( parameters.length == 0) //zero-parameter
return adapterConstructor;
}
}
throw new NoSuchElementException( "No Valid Constructor Found for: " + adapterClass.getName());
}
/**
* Returns the adapter class for the given config object.
*
* @see SCAdapter#adapterConstructorFor( Object)
*/
private final Class adapterClassFor( Object configObject) {
String configClassName = ClassTools.shortNameFor( configObject.getClass());
return adapterClassNamed( configClassName);
}
/**
* Helper method that returns the Adapter class for the given config class name.
*
* @throws NoSuchElementException when scModelClass is not found.
*/
static final Class adapterClassNamed( String configClassName) {
String adapterClassName = adapterPackageName
+ configClassName.substring( 0, configClassName.lastIndexOf( modelClassSuffix))
+ adapterClassSuffix;
Class adapterClass = null;
try {
adapterClass = ClassTools.classForName( adapterClassName);
}
catch( RuntimeException e) {
throw new NoSuchElementException( "Adapter Class Not Known For SC Model Class: " + configClassName);
}
return adapterClass;
}
/**
* Builds an SCAdapter with the given constructor.
*/
static final SCAdapter buildsAdapterWith( Constructor adapterConstructor, Object[] parameters) {
SCAdapter newAdapter = null;
try {
newAdapter = ( SCAdapter)adapterConstructor.newInstance( parameters);
}
catch( InvocationTargetException ite) {
throw new RuntimeException("InvocationTarget Exception When Instantiating " + adapterConstructor.getName(), ite);
}
catch( InstantiationException ie) {
throw new RuntimeException("Instantiation Exception When Instantiating " + adapterConstructor.getName(), ie);
}
catch( IllegalAccessException iae) {
throw new RuntimeException("Illegal Access Exception When Instantiating " + adapterConstructor.getName(), iae);
}
return newAdapter;
}
/**
* Initializes this model from config.
*/
protected void initializeFromModel( Object configObject) {
this.setModel( configObject);
}
/**
* Post Initialization: allows validation, handle legacy model...
*/
protected void postInitializationFromModel() {
for( Iterator iter = children(); iter.hasNext(); ) {
(( SCAdapter) iter.next()).postInitializationFromModel();
}
}
/**
* Initializes this new instance.
*/
protected void initialize() {
super.initialize();
this.setConfigRequired( false);
}
/**
* Initializes this new model inst. var. and aggregates.
*/
protected void initialize( Object newConfig) {
this.setModel( newConfig);
}
/**
* Initializes this new model defaults.
* Default behavior is to do nothing.
*/
protected void initializeDefaults() {
return;
}
}