/*
* Chrysalix
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
* See the AUTHORS.txt file in the distribution for a full listing of
* individual contributors.
*
* Chrysalix is free software. Unless otherwise indicated, all code in Chrysalix
* is licensed to you under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Chrysalix 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 this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.chrysalix.operation;
import org.chrysalix.ChrysalixException;
import org.chrysalix.ChrysalixI18n;
import org.chrysalix.ChrysalixLexicon;
import org.chrysalix.common.CheckArg;
import org.chrysalix.transformation.Operation;
import org.chrysalix.transformation.TransformationFactory;
import org.chrysalix.transformation.Value;
import org.chrysalix.transformation.ValueDescriptor;
import org.modelspace.Model;
import org.modelspace.ModelObject;
import org.modelspace.ModelProperty;
import org.modelspace.ModelspaceException;
/**
* The base class for {@link Value value} transformation objects.
*
* @param <T>
* the value type
*/
public class ValueImpl< T > implements Value< T > {
private static final String DESCRIPTOR_ERROR = "Error obtaining input descriptor '%s.'";
private static final String PATH_ERROR = "Error obtaining absolute path for input descriptor '%s.'";
private static final String ERROR_GETTING_PATH_VALUE = "Error obtaining path value for input descriptor '%s.'";
private static final String ERROR_GETTING_VALUE = "Error obtaining value for input descriptor '%s.'";
private static final String ERROR_SETTING_VALUE = "Error setting value for input descriptor '%s.'";
private static final String TRANSFORMATION_FACTORY_ERROR = "Unable to obtain transformation factory";
static final String VALUE_NOT_MODIFIABLE = "The value '%s' is not modifiable";
private final String descriptorId;
private final ModelObject input;
/**
* @param descriptorId
* the ID of the descriptor for this input (cannot be <code>null</code> or empty)
* @param modelObject
* the model object for this value (cannot be <code>null</code>)
*/
public ValueImpl( final String descriptorId,
final ModelObject modelObject ) {
CheckArg.notEmpty( descriptorId, "descriptorId" );
CheckArg.notNull( modelObject, "modelObject" );
this.descriptorId = descriptorId;
this.input = modelObject;
}
/**
* {@inheritDoc}
*
* @see org.modelspace.ModelElement#absolutePath()
*/
@Override
public String absolutePath() throws ModelspaceException {
return this.input.absolutePath();
}
@SuppressWarnings( "unchecked" )
private ValueDescriptor< T > descriptor() throws ChrysalixException {
try {
final TransformationFactory factory = TransformationFactory.REGISTRY.get( this.input.model().modelspace() );
return ( ValueDescriptor< T > ) factory.descriptor( this.descriptorId );
} catch ( final ModelspaceException e ) {
throw new ChrysalixException( e, ChrysalixI18n.localize( TRANSFORMATION_FACTORY_ERROR ) );
}
}
/**
* {@inheritDoc}
*
* @see org.chrysalix.transformation.Value#descriptorId()
*/
@SuppressWarnings( "unused" )
@Override
public String descriptorId() throws ChrysalixException {
return this.descriptorId;
}
/**
* @param proposedValue
* the proposed new value (can be <code>null</code>)
* @return <code>true</code> if proposed value is a {@link ModelProperty model property} or an {@link Operation operation}
* @throws ChrysalixException
* if an error occurs
*/
protected boolean determinePathValueBasedOn( final Object proposedValue ) throws ChrysalixException {
return ( proposedValue instanceof ModelObject );
}
/**
* @param proposedValue
* the proposed new value (can be <code>null</code>)
* @return the new value based on using the specified proposed value (can be <code>null</code>)
* @throws ChrysalixException
* if an error occurs
*/
protected Object determineValueBasedOn( final Object proposedValue ) throws ChrysalixException {
if ( ( proposedValue instanceof ModelProperty ) || ( proposedValue instanceof Operation< ? > ) ) {
try {
return ( ( ModelObject ) proposedValue ).modelRelativePath();
} catch ( final ModelspaceException e ) {
throw new ChrysalixException( e, ChrysalixI18n.localize( PATH_ERROR, this.descriptorId ) );
}
}
return proposedValue;
}
/**
* {@inheritDoc}
*
* @see org.chrysalix.transformation.Value#get()
*/
@SuppressWarnings( { "unchecked" } )
@Override
public T get() throws ChrysalixException {
if ( this.input instanceof Operation< ? > ) {
return ( ( Operation< T > ) this.input ).get();
}
boolean valueIsPath = false;
try {
if ( this.input.hasProperty( ChrysalixLexicon.Input.PATH ) ) {
valueIsPath = this.input.property( ChrysalixLexicon.Input.PATH ).booleanValue();
}
final boolean hasValue = this.input.hasProperty( ChrysalixLexicon.Input.VALUE );
if ( valueIsPath ) {
// value is a model property path
if ( hasValue ) {
final String propPath = this.input.property( ChrysalixLexicon.Input.VALUE ).stringValue();
final ModelProperty modelProperty = this.model().property( propPath );
if ( modelProperty.descriptor().multiple() ) {
return ( T ) modelProperty.values();
}
return ( T ) modelProperty.value();
}
throw new ChrysalixException( ChrysalixI18n.localize( ERROR_GETTING_PATH_VALUE, this.descriptorId ) );
}
// value is a literal
if ( hasValue ) {
return ( T ) this.input.property( ChrysalixLexicon.Input.VALUE ).value();
}
return null; // no value set
} catch ( final Exception pe ) {
throw new ChrysalixException( ChrysalixI18n.localize( ERROR_GETTING_VALUE, this.descriptorId ) );
}
}
/**
* {@inheritDoc}
*
* @see org.modelspace.ModelElement#model()
*/
@Override
public Model model() throws ModelspaceException {
return this.input.model();
}
/**
* {@inheritDoc}
*
* @see org.chrysalix.transformation.Value#modelObect()
*/
@Override
public ModelObject modelObect() {
return this.input;
}
/**
* {@inheritDoc}
*
* @see org.modelspace.ModelElement#modelRelativePath()
*/
@Override
public String modelRelativePath() throws ModelspaceException {
return this.input.modelRelativePath();
}
/**
* {@inheritDoc}
*
* @see org.modelspace.ModelElement#name()
*/
@Override
public String name() throws ModelspaceException {
return this.input.name();
}
/**
* {@inheritDoc}
*
* @see org.chrysalix.transformation.Value#set(java.lang.Object)
*/
@Override
public void set( final Object proposedValue ) throws ChrysalixException {
if ( !descriptor().modifiable() ) {
throw new UnsupportedOperationException( ChrysalixI18n.localize( VALUE_NOT_MODIFIABLE, this.descriptorId ) );
}
boolean isPath = false;
Object newValue = null;
if ( proposedValue != null ) {
newValue = determineValueBasedOn( proposedValue );
isPath = determinePathValueBasedOn( proposedValue );
}
try {
this.input.setProperty( ChrysalixLexicon.Input.PATH, isPath );
this.input.setProperty( ChrysalixLexicon.Input.VALUE, newValue );
} catch ( final ModelspaceException e ) {
throw new UnsupportedOperationException( ChrysalixI18n.localize( ERROR_SETTING_VALUE, this.descriptorId ) );
}
}
/**
* {@inheritDoc}
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
try {
return descriptor().toString();
} catch ( final Exception e ) {
return ChrysalixI18n.localize( DESCRIPTOR_ERROR, this.descriptorId );
}
}
}