/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* 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.
*
* This software 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.jboss.system.server.profileservice.persistence;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jboss.logging.Logger;
import org.jboss.metatype.api.types.ArrayMetaType;
import org.jboss.metatype.api.types.CollectionMetaType;
import org.jboss.metatype.api.types.CompositeMetaType;
import org.jboss.metatype.api.types.EnumMetaType;
import org.jboss.metatype.api.types.GenericMetaType;
import org.jboss.metatype.api.types.MapCompositeMetaType;
import org.jboss.metatype.api.types.MetaType;
import org.jboss.metatype.api.types.Name;
import org.jboss.metatype.api.types.PropertiesMetaType;
import org.jboss.metatype.api.types.SimpleMetaType;
import org.jboss.metatype.api.types.TableMetaType;
import org.jboss.metatype.api.values.ArrayValue;
import org.jboss.metatype.api.values.ArrayValueSupport;
import org.jboss.metatype.api.values.CollectionValue;
import org.jboss.metatype.api.values.CollectionValueSupport;
import org.jboss.metatype.api.values.CompositeValue;
import org.jboss.metatype.api.values.CompositeValueSupport;
import org.jboss.metatype.api.values.EnumValue;
import org.jboss.metatype.api.values.EnumValueSupport;
import org.jboss.metatype.api.values.GenericValue;
import org.jboss.metatype.api.values.GenericValueSupport;
import org.jboss.metatype.api.values.MapCompositeValueSupport;
import org.jboss.metatype.api.values.MetaValue;
import org.jboss.metatype.api.values.PropertiesMetaValue;
import org.jboss.metatype.api.values.SimpleValue;
import org.jboss.metatype.api.values.SimpleValueSupport;
import org.jboss.metatype.api.values.TableValue;
import org.jboss.metatype.api.values.TableValueSupport;
import org.jboss.metatype.plugins.types.StringName;
import org.jboss.reflect.plugins.ValueConvertor;
import org.jboss.system.server.profileservice.persistence.xml.NullValue;
import org.jboss.system.server.profileservice.persistence.xml.PersistedArrayValue;
import org.jboss.system.server.profileservice.persistence.xml.PersistedCollectionValue;
import org.jboss.system.server.profileservice.persistence.xml.PersistedCompositeValue;
import org.jboss.system.server.profileservice.persistence.xml.PersistedEnumValue;
import org.jboss.system.server.profileservice.persistence.xml.PersistedGenericValue;
import org.jboss.system.server.profileservice.persistence.xml.PersistedPair;
import org.jboss.system.server.profileservice.persistence.xml.PersistedPropertiesValue;
import org.jboss.system.server.profileservice.persistence.xml.PersistedSimpleValue;
import org.jboss.system.server.profileservice.persistence.xml.PersistedTableValue;
import org.jboss.system.server.profileservice.persistence.xml.PersistedValue;
/**
* The abstract value recreation creates MetaValues based on the persisted
* managed object information and the MetaTypes of the ManagedObject used
* for persistence. The recreation of ManagedObjects itself is delegated
* to a ManagedObjectRecreationPlugin.
*
* @author <a href="mailto:emuckenh@redhat.com">Emanuel Muckenhuber</a>
* @version $Revision$
*/
public class AbstractValueRecreation
{
/** The simple types. */
private final static Map<String, Class<? extends Serializable>> simpleTypes = new HashMap<String, Class<? extends Serializable>>();
/** The logger. */
private final static Logger log = Logger.getLogger(AbstractValueRecreation.class);
/** The recreation plugin. */
private final ManagedObjectPersistencePlugin plugin;
static
{
// Fill simple types map.
simpleTypes.put(BigDecimal.class.getName(), BigDecimal.class);
simpleTypes.put(BigInteger.class.getName(), BigInteger.class);
simpleTypes.put(Boolean.class.getName(), Boolean.class);
simpleTypes.put(Byte.class.getName(), Byte.class);
simpleTypes.put(Character.class.getName(), Character.class);
simpleTypes.put(Date.class.getName(), Date.class);
simpleTypes.put(Double.class.getName(), Double.class);
simpleTypes.put(Float.class.getName(), Float.class);
simpleTypes.put(Integer.class.getName(), Integer.class);
simpleTypes.put(Long.class.getName(), Long.class);
simpleTypes.put(Short.class.getName(), Short.class);
simpleTypes.put(String.class.getName(), String.class);
simpleTypes.put(Name.class.getName(), Name.class);
// primitive classes
simpleTypes.put(byte.class.getName(), byte.class);
simpleTypes.put(char.class.getName(), char.class);
simpleTypes.put(double.class.getName(), double.class);
simpleTypes.put(float.class.getName(), float.class);
simpleTypes.put(int.class.getName(), int.class);
simpleTypes.put(short.class.getName(), short.class);
simpleTypes.put(long.class.getName(), long.class);
simpleTypes.put(boolean.class.getName(), boolean.class);
}
public AbstractValueRecreation(ManagedObjectPersistencePlugin callback)
{
if(callback == null)
throw new IllegalArgumentException("null managed object persistence callback");
this.plugin = callback;
}
public ManagedObjectPersistencePlugin getPlugin()
{
return plugin;
}
/**
* Create the meta value, based on the xml persisted
* value and the generated MetaType.
*
* @param valueElement the persisted xml element
* @param type the meta type
* @return the created meta value
*/
public MetaValue createMetaValue(PersistedValue valueElement, MetaType metaType)
{
if(log.isTraceEnabled())
{
log.trace("processing value " + valueElement + " type: " + metaType);
}
if(valueElement instanceof NullValue)
return null;
if(valueElement == null)
return null;
MetaValue metaValue = null;
try
{
if(metaType.isSimple())
{
metaValue = createSimpleValue(
(PersistedSimpleValue) valueElement,
(SimpleMetaType) metaType);
}
else if(metaType.isEnum())
{
metaValue = createEnumValue(
(PersistedEnumValue) valueElement,
(EnumMetaType) metaType);
}
else if(metaType.isCollection())
{
metaValue = createCollectionValue(
(PersistedCollectionValue) valueElement,
(CollectionMetaType) metaType);
}
else if(metaType.isGeneric())
{
metaValue = createGenericValue(
(PersistedGenericValue) valueElement,
(GenericMetaType) metaType);
}
else if(metaType.isComposite())
{
metaValue = createCompositeValue(
(PersistedCompositeValue) valueElement,
(CompositeMetaType) metaType);
}
else if(metaType.isTable())
{
metaValue = createTableValue(
(PersistedTableValue) valueElement,
(TableMetaType)metaType);
}
else if(metaType.isArray())
{
metaValue = createArrayValue(
(PersistedArrayValue) valueElement,
(ArrayMetaType) metaType);
}
else if(metaType.isProperties())
{
metaValue = createPropertiesValue(
(PersistedPropertiesValue) valueElement,
(PropertiesMetaType) metaType);
}
else
{
throw new IllegalStateException("unknown metaType");
}
}
finally
{
//
}
return metaValue;
}
/**
* Create simple value.
*
* @param valueElement the persisted xml meta data
* @param value the simple value
* @return a simple value
*/
protected SimpleValue createSimpleValue(PersistedSimpleValue valueElement, SimpleMetaType metaType)
{
String elementValue = valueElement.getValue();
Serializable converted = null;
if(elementValue != null)
{
if(metaType.equals(SimpleMetaType.STRING))
{
converted = (String) elementValue;
}
else if (metaType.equals(SimpleMetaType.NAMEDOBJECT))
{
converted = new StringName(elementValue);
}
else if (metaType.equals(SimpleMetaType.VOID))
{
//
}
else
{
converted = convert2Type(metaType.getTypeName(), elementValue);
}
}
return new SimpleValueSupport(metaType, converted);
}
/**
* Process an Enum value.
*
* @param enumElement the persisted xml meta data
* @param value the enum value
* @return a enum value
*/
protected EnumValue createEnumValue(PersistedEnumValue enumElement, EnumMetaType type)
{
return new EnumValueSupport(type, enumElement.getValue());
}
/**
* Create composite value.
*
* @param composite the persisted xml meta data
* @param value the composite value
* @return a composite value
*/
protected CompositeValue createCompositeValue(PersistedCompositeValue composite, CompositeMetaType type)
{
// Handle the mapCompositeMetaType differently
if(type instanceof MapCompositeMetaType)
return handleMapCompositeMetaType(composite, (MapCompositeMetaType) type);
// Create composite value
Map<String, MetaValue> values = new HashMap<String, MetaValue>();
if(composite.getValues() != null && composite.getValues().isEmpty() == false)
{
for(PersistedValue persistedValue : composite.getValues())
{
MetaType elementType = type.getType(persistedValue.getName());
if(elementType == null)
throw new IllegalStateException("Failed to process composite value: " + persistedValue.getName());
// Create
MetaValue metaValue = createMetaValue(persistedValue, elementType);
// Put
values.put(persistedValue.getName(), metaValue);
}
}
return new CompositeValueSupport(type, values);
}
/**
* Create the MapCompositeValueSupport value.
*
* @param composite the persisted composite xml meta data
* @param type the MapComposite meta type
* @return the MapCompositeValueSupport
*/
protected MapCompositeValueSupport handleMapCompositeMetaType(PersistedCompositeValue composite, MapCompositeMetaType type)
{
Map<String, MetaValue> values = new HashMap<String, MetaValue>();
if(composite.getValues() != null && composite.getValues().isEmpty() == false)
{
for(PersistedValue persistedValue : composite.getValues())
{
MetaValue value = createMetaValue(persistedValue, type.getValueType());
values.put(persistedValue.getName(), value);
}
}
return new MapCompositeValueSupport(values, type);
}
/**
* Process a collection.
*
* @param collection the persisted xml meta data
* @param value the collection value
* @return a collection value
*/
protected CollectionValue createCollectionValue(PersistedCollectionValue collection, CollectionMetaType type)
{
List<MetaValue> elementList = new ArrayList<MetaValue>();
if(collection.getValues() != null && collection.getValues().isEmpty() == false)
{
for(PersistedValue element : collection.getValues())
{
elementList.add(
createMetaValue(element, type.getElementType()));
}
}
return new CollectionValueSupport(type, elementList.toArray(new MetaValue[elementList.size()]));
}
/**
* Create generic value.
*
* @param genericElement the persisted generic xml meta data
* @param metaType the generic meta type
* @return the generic value
*/
protected GenericValue createGenericValue(PersistedGenericValue genericElement, GenericMetaType metaType)
{
Serializable value = null;
if(genericElement.getManagedObject() != null)
{
value = getPlugin().createManagedObject(genericElement.getManagedObject());
}
return new GenericValueSupport(metaType, value);
}
/**
* Create the table value.
*
* @param table the persisted table value
* @param type the table meta type
* @return the table value
*/
protected TableValue createTableValue(PersistedTableValue table, TableMetaType type)
{
TableValueSupport support = new TableValueSupport(type);
if(table.getEntries() != null && table.getEntries().isEmpty() == false)
{
for(PersistedCompositeValue entry : table.getEntries())
{
support.put(createCompositeValue(entry, type.getRowType()));
}
}
return support;
}
/**
* Create the properties value.
*
* @param value the persisted properties value
* @param metaType the properties meta type
* @return the properties value
*/
protected MetaValue createPropertiesValue(
PersistedPropertiesValue value, PropertiesMetaType metaType)
{
PropertiesMetaValue properties = new PropertiesMetaValue();
for(PersistedPair pair : value.getEntries())
{
properties.setProperty(pair.getKey(), pair.getValue());
}
return properties;
}
/**
* Create array value.
*
* @param valueElement the persisted array xml value
* @param type the array meta type
* @return the array value
*/
@SuppressWarnings("unchecked")
protected ArrayValue createArrayValue(PersistedArrayValue valueElement, ArrayMetaType type)
{
int size = valueElement.size();
List values = new ArrayList(size);
for(PersistedValue elementValue : valueElement.getValues())
{
if(elementValue instanceof PersistedArrayValue)
{
values.add(
recreateArrayValue((PersistedArrayValue) elementValue, type.getElementType()));
}
else
{
MetaValue value = createMetaValue(elementValue, type.getElementType());
values.add(value);
}
}
return new ArrayValueSupport(type, values.toArray());
}
/**
* Recreate the array values.
*
* @param valueElement the persisted xml value
* @param type the element type
* @return the recreated array
*/
@SuppressWarnings("unchecked")
protected Object recreateArrayValue(PersistedArrayValue valueElement, MetaType type)
{
List values = new ArrayList(valueElement.size());
for(PersistedValue elementValue : valueElement.getValues())
{
if(elementValue instanceof PersistedArrayValue)
{
values.add(
recreateArrayValue((PersistedArrayValue) elementValue, type));
}
else
{
MetaValue value = createMetaValue(elementValue, type);
values.add(value);
}
}
return values.toArray();
}
/**
* Convert simple types.
*
* @param clazz a primitive serializable class.
* @param value the String
* @return the converted object, null in case of any failure.
*/
public Serializable convert2Type(String className, String value)
{
if(value == null)
return null;
Class<?> clazz = simpleTypes.get(className);
if(clazz == null)
throw new IllegalStateException("Cannot find simple type entry for "+ value + " and class "+ className);
try
{
return (Serializable) ValueConvertor.convertValue(clazz, value);
}
catch(Throwable t)
{
log.debug("could convert "+ value +" to " + clazz.getName());
return null;
}
}
}