getPluginRecordClass(String pluginName)
+ throws PluginException {
+ try {
+ return getPluginClass(pluginName);
+ } catch (NoPluginException e) {
+ throw new PluginException(e.getLocalizedMessage());
+ }
+ }
}
\ No newline at end of file
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin/src/com/raytheon/uf/common/dataplugin/IPluginClassMapper.java b/edexOsgi/com.raytheon.uf.common.dataplugin/src/com/raytheon/uf/common/dataplugin/IPluginClassMapper.java
new file mode 100644
index 0000000000..cb03d67927
--- /dev/null
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin/src/com/raytheon/uf/common/dataplugin/IPluginClassMapper.java
@@ -0,0 +1,45 @@
+/**
+ * This software was developed and / or modified by Raytheon Company,
+ * pursuant to Contract DG133W-05-CQ-1067 with the US Government.
+ *
+ * U.S. EXPORT CONTROLLED TECHNICAL DATA
+ * This software product contains export-restricted data whose
+ * export/transfer/disclosure is restricted by U.S. law. Dissemination
+ * to non-U.S. persons whether in the United States or abroad requires
+ * an export license or other authorization.
+ *
+ * Contractor Name: Raytheon Company
+ * Contractor Address: 6825 Pine Street, Suite 340
+ * Mail Stop B8
+ * Omaha, NE 68106
+ * 402.291.0100
+ *
+ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for
+ * further licensing information.
+ **/
+package com.raytheon.uf.common.dataplugin;
+
+
+/**
+ * Interface for any class that is capable of mapping a pluginName to a class
+ * which extends PluginDataObject. This interface exists in common so that
+ * different mechanisms can easily be used in different parts of the system.
+ *
+ *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date Ticket# Engineer Description
+ * ------------ ---------- ----------- --------------------------
+ * May 16, 2013 1869 bsteffen Initial creation
+ *
+ *
+ *
+ * @author bsteffen
+ * @version 1.0
+ */
+public interface IPluginClassMapper {
+
+ public Class getPluginRecordClass(String pluginName)
+ throws PluginException;
+}
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin/src/com/raytheon/uf/common/dataplugin/PluginDataObject.java b/edexOsgi/com.raytheon.uf.common.dataplugin/src/com/raytheon/uf/common/dataplugin/PluginDataObject.java
index 417f84f26c..202bbc97a4 100644
--- a/edexOsgi/com.raytheon.uf.common.dataplugin/src/com/raytheon/uf/common/dataplugin/PluginDataObject.java
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin/src/com/raytheon/uf/common/dataplugin/PluginDataObject.java
@@ -20,10 +20,7 @@
package com.raytheon.uf.common.dataplugin;
-import java.lang.reflect.Field;
import java.util.Calendar;
-import java.util.HashMap;
-import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Embedded;
@@ -40,7 +37,6 @@ import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
-import org.apache.commons.beanutils.PropertyUtils;
import org.hibernate.annotations.Index;
import com.raytheon.uf.common.dataplugin.annotations.DataURI;
@@ -52,9 +48,10 @@ import com.raytheon.uf.common.serialization.ISerializableObject;
import com.raytheon.uf.common.serialization.SerializationUtil;
import com.raytheon.uf.common.serialization.annotations.DynamicSerialize;
import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement;
+import com.raytheon.uf.common.status.IUFStatusHandler;
+import com.raytheon.uf.common.status.UFStatus;
+import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.common.time.DataTime;
-import com.raytheon.uf.common.time.util.TimeUtil;
-import com.raytheon.uf.common.util.ConvertUtil;
/**
* Abstract class from which all plugin specific data types inherit. A plugin
@@ -88,21 +85,24 @@ import com.raytheon.uf.common.util.ConvertUtil;
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
- * 7/24/07 353 bphillip Initial creation
- * 20071129 472 jkorman Added getDecoderGettable().
- * 2/6/09 1990 bphillip Added database index on dataURI
- * 3/18/09 2105 jsanchez Added getter for id.
- * Removed unused getIdentfier().
- * Mar 29, 2013 1638 mschenke Added methods for loading from data map and creating data map from
- * dataURI fields
- * Apr 12, 2013 1857 bgonzale Changed to MappedSuperclass, named generator,
- * GenerationType SEQUENCE, moved Indexes to getter
- * methods.
+ * Jul 24, 2007 353 bphillip Initial creation
+ * Nov 29, 2007 472 jkorman Added getDecoderGettable().
+ * Feb 06, 2009 1990 bphillip Added database index on dataURI
+ * Mar 18, 2009 2105 jsanchez Added getter for id. Removed unused
+ * getIdentfier().
+ * Mar 29, 2013 1638 mschenke Added methods for loading from data map
+ * and creating data map from dataURI
+ * fields
+ * Apr 12, 2013 1857 bgonzale Changed to MappedSuperclass, named
+ * generator, GenerationType SEQUENCE,
+ * moved Indexes to getter methods.
* Apr 15, 2013 1868 bsteffen Improved performance of createDataURIMap
- * May 02, 2013 1970 bgonzale Moved Index annotation from getters to attributes.
- *
+ * May 02, 2013 1970 bgonzale Moved Index annotation from getters to
+ * attributes.
* May 07, 2013 1869 bsteffen Remove dataURI column from
* PluginDataObject.
+ * May 16, 2013 1869 bsteffen Rewrite dataURI property mappings.
+ *
*
*/
@MappedSuperclass
@@ -112,6 +112,9 @@ import com.raytheon.uf.common.util.ConvertUtil;
public abstract class PluginDataObject extends PersistableDataObject implements
ISerializableObject {
+ private static final transient IUFStatusHandler statusHandler = UFStatus
+ .getHandler(PluginDataObject.class);
+
private static final long serialVersionUID = 1L;
public static final String ID_GEN = "idgen";
@@ -159,12 +162,16 @@ public abstract class PluginDataObject extends PersistableDataObject implements
* Default Constructor
*/
public PluginDataObject() {
+
}
public PluginDataObject(String uri) {
- String[] uriTokens = uri.split(DataURI.SEPARATOR);
- pluginName = uriTokens[1];
- populateObject(this, uriTokens);
+ try {
+ DataURIUtil.populatePluginDataObject(this, uri);
+ } catch (PluginException e) {
+ // this should never happen operationally
+ statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(), e);
+ }
this.dataURI = uri;
}
@@ -178,344 +185,19 @@ public abstract class PluginDataObject extends PersistableDataObject implements
getDataURI();
}
- /**
- * Recursive method for generating a dataURI
- *
- * @param obj
- * An object containing fields annotated with the DataURI
- * annotation
- * @param uriBuffer
- * The dataURI StringBuffer
- * @return The updated dataURI
- */
- private void generateURI(Object obj, StringBuilder uriBuffer) {
-
- // Get the fields with @DataURI annotation
- Field[] dataURIFields = DataURIUtil.getInstance().getDataURIFields(
- obj.getClass());
-
- /*
- * Iterate through each field and assemble the dataURI
- */
- for (Field field : dataURIFields) {
- Object property = null;
- try {
- property = PropertyUtils.getProperty(obj, field.getName());
- } catch (Exception e) {
- e.printStackTrace();
- }
- if (field.getAnnotation(DataURI.class).embedded()) {
- if (property == null) {
- // Populate datauri with all "null" for null embedded
- // objects.
- int numFields = DataURIUtil.getInstance().getDataURIFields(
- field.getClass()).length;
- for (int f = 0; f < numFields; f += 1) {
- uriBuffer.append(DataURI.SEPARATOR).append(
- String.valueOf(null));
- }
- } else {
- // Recursive call to get dataURI elements from embedded
- // object
- generateURI(property, uriBuffer);
- }
- } else {
- // Append to the dataURI buffer
- uriBuffer.append(DataURI.SEPARATOR);
- if (property == null) {
- uriBuffer.append("null");
- } else if (property instanceof Calendar) {
- uriBuffer.append(TimeUtil
- .formatCalendar((Calendar) property));
- } else {
- uriBuffer.append(String.valueOf(property).replaceAll(
- DataURI.SEPARATOR, "_"));
- }
- }
- }
- }
-
- /**
- * Populates the record object from a data map
- *
- * @param dataMap
- * @throws PluginException
- */
- public void populateFromMap(Map dataMap)
- throws PluginException {
- populateFromMap(this, dataMap);
- }
-
- /**
- * Creates a mapping of dataURI fields to objects set in the record
- *
- * @return
- * @throws PluginException
- */
- public Map createDataURIMap() throws PluginException {
- try {
- Class extends PluginDataObject> thisClass = this.getClass();
- Map map = new HashMap();
- map.put("pluginName", getPluginName());
- int index = 0;
- String fieldName = PluginDataObject.getDataURIFieldName(thisClass,
- index++);
- while (fieldName != null) {
- Object source = this;
- int start = 0;
- int end = fieldName.indexOf('.', start);
- while (end >= 0) {
- source = PropertyUtils.getProperty(source,
- fieldName.substring(start, end));
- start = end + 1;
- end = fieldName.indexOf('.', start);
- }
- source = PropertyUtils.getProperty(source,
- fieldName.substring(start));
- map.put(fieldName, source);
- fieldName = PluginDataObject.getDataURIFieldName(thisClass,
- index++);
- }
- return map;
- } catch (Exception e) {
- throw new PluginException("Error constructing dataURI mapping", e);
- }
- }
-
- /**
- * Populates object from data mapping
- *
- * @param object
- * @param dataMap
- */
- public static void populateFromMap(Object object,
- Map dataMap) throws PluginException {
- try {
- for (String property : dataMap.keySet()) {
- String[] nested = property.split("[.]");
- if (nested.length > 0) {
- Object source = object;
- for (int i = 0; i < nested.length - 1; ++i) {
- String field = nested[i];
- Object obj = PropertyUtils.getProperty(source, field);
- if (obj == null) {
- obj = PropertyUtils.getPropertyType(source, field)
- .newInstance();
- PropertyUtils.setProperty(source, field, obj);
- }
- source = obj;
- }
- String sourceProperty = nested[nested.length - 1];
- Object value = dataMap.get(property);
- if (value != null) {
- PropertyUtils
- .setProperty(source, sourceProperty, value);
- }
- }
- }
- } catch (Exception e) {
- throw new PluginException("Error populating record type: "
- + (object != null ? object.getClass() : null)
- + " from map: " + dataMap, e);
- }
- }
-
- /**
- * Recursive method to populate an object from the elements in a dataURI
- * string
- *
- * @param obj
- * The object for which to populate fields from the dataURI
- * string
- * @param uriTokens
- * The elements of the dataURI string
- * @return An object populated from the elements of the dataURI string
- */
- @SuppressWarnings("unchecked")
- private Object populateObject(Object obj, String[] uriTokens) {
-
- // Get the fields annotated with the @DataURI annotation
- Field[] dataURIFields = DataURIUtil.getInstance().getDataURIFields(
- obj.getClass());
-
- Field currentField = null;
- String currentUriToken = null;
- for (Field dataURIField : dataURIFields) {
- currentUriToken = uriTokens[uriIndex];
- currentField = dataURIField;
-
- if (currentField.getAnnotation(DataURI.class).embedded()) {
- // The current dataURI token refers to a field in an embedded
- // object. Execute recursive call to populate embedded object
- try {
- if (obj instanceof Map) {
- populateObject(obj, uriTokens);
- } else {
- PropertyUtils.setProperty(
- obj,
- currentField.getName(),
- populateObject(currentField.getType()
- .newInstance(), uriTokens));
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- } else {
- // The current dataURI token refers to field in the obj class.
- // Assign the field and increment the uri index variable
- uriIndex++;
- try {
- Object property = ConvertUtil.convertObject(
- currentUriToken, currentField.getType());
- if (obj instanceof Map) {
- ((Map) obj).put(currentField.getName(),
- property);
- } else {
- try {
- PropertyUtils.setProperty(obj,
- currentField.getName(), property);
- } catch (Throwable e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- return obj;
- }
-
- /**
- * Retrieves the name of the field represented by the specified index in the
- * dataURI. The index starts at the dataTime in the dataURI and does not
- * include the plugin name.
- *
- * @param clazz
- * The class of the object to examine
- * @param targetIndex
- * The index in the dataURI
- * @return The name of the field at the specified dataURI index
- */
- public static String getDataURIFieldName(Class> clazz, int targetIndex) {
- return getDataURIFieldName(targetIndex, new int[] { 0 }, clazz, "");
- }
-
- /**
- * Recursive method to get the dataURI field name
- *
- * @param targetIndex
- * The index in the DataURI to get the field name for
- * @param index
- * The current index being examined. This field is necessary for
- * recursive calls
- * @param clazz
- * The class being examined
- * @param fieldName
- * The current field name. This field is necessary for recursive
- * calls. If the dataURI is specified in an embedded object, this
- * field will take the form class1.class2.field i.e. for a grib
- * record this could be modelInfo.modelName
- * @return The fieldName
- */
- private static String getDataURIFieldName(int targetIndex, int[] index,
- Class> clazz, String fieldName) {
- // Get the fields annotated with the @DataURI annotation
- Field[] dataURIFields = DataURIUtil.getInstance().getDataURIFields(
- clazz);
-
- for (Field field : dataURIFields) {
-
- DataURI uriAnnotation = field.getAnnotation(DataURI.class);
- if (uriAnnotation != null) {
- if (uriAnnotation.embedded()) {
- String tmp = getDataURIFieldName(targetIndex, index,
- field.getType(), fieldName + field.getName() + ".");
- if (tmp != null) {
- return tmp;
- }
- } else {
- if (index[0] == targetIndex) {
- fieldName += field.getName();
- return fieldName;
- } else {
- index[0]++;
- }
- }
- }
- }
- return null;
- }
-
- /**
- * Gets the value in the dataURI at the specified index
- *
- * @param index
- * The index in the dataURI for which to get the value
- * @param fieldName
- * The name of the field
- * @return The value in the dataURI at the specified index
- * @throws Exception
- */
- public Object getDataURIFieldValue(int index, String fieldName)
- throws Exception {
- return getDataURIFieldValue(index, new int[] { 0 }, this.getClass(),
- fieldName);
- }
-
- /**
- * Recursive helper method to get a dataURI field value
- *
- * @param targetIndex
- * The index in the dataURI for which to get the value
- * @param index
- * The current index in the dataURI being examined
- * @param clazz
- * The class to be examined
- * @param fieldName
- * The name of the field
- * @return The value in the dataURI at the specified index
- * @throws Exception
- */
- private Object getDataURIFieldValue(int targetIndex, int[] index,
- Class> clazz, String fieldName) throws Exception {
- // Get the fields annotated with the @DataURI annotation
- Field[] dataURIFields = DataURIUtil.getInstance().getDataURIFields(
- clazz);
-
- for (Field field : dataURIFields) {
- DataURI uriAnnotation = field.getAnnotation(DataURI.class);
- if (uriAnnotation != null) {
- if (uriAnnotation.embedded()) {
- Object tmp = getDataURIFieldValue(targetIndex, index,
- field.getType(), fieldName);
- if (tmp != null) {
- return tmp;
- }
- } else {
- if (index[0] == targetIndex) {
- return ConvertUtil.convertObject(fieldName,
- field.getType());
- } else {
- index[0]++;
- }
- }
- }
- }
- return null;
- }
-
public DataTime getDataTime() {
return dataTime;
}
public String getDataURI() {
if (dataURI == null && pluginName != null) {
- StringBuilder uriBuffer = new StringBuilder(160);
- uriBuffer.append(DataURI.SEPARATOR).append(pluginName);
- generateURI(this, uriBuffer);
- this.dataURI = uriBuffer.toString().replaceAll(" ", "_");
+ try {
+ this.dataURI = DataURIUtil.createDataURI(this);
+ } catch (PluginException e) {
+ // this should never happen operationally
+ statusHandler.handle(Priority.PROBLEM, e.getLocalizedMessage(),
+ e);
+ }
}
return this.dataURI;
}
diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin/src/com/raytheon/uf/common/dataplugin/annotations/DataURIUtil.java b/edexOsgi/com.raytheon.uf.common.dataplugin/src/com/raytheon/uf/common/dataplugin/annotations/DataURIUtil.java
index 5416eb0d62..3a6ad3edcd 100644
--- a/edexOsgi/com.raytheon.uf.common.dataplugin/src/com/raytheon/uf/common/dataplugin/annotations/DataURIUtil.java
+++ b/edexOsgi/com.raytheon.uf.common.dataplugin/src/com/raytheon/uf/common/dataplugin/annotations/DataURIUtil.java
@@ -23,14 +23,22 @@ package com.raytheon.uf.common.dataplugin.annotations;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Pattern;
import org.apache.commons.beanutils.PropertyUtils;
+import com.raytheon.uf.common.dataplugin.IPluginClassMapper;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.PluginException;
+import com.raytheon.uf.common.time.util.TimeUtil;
+import com.raytheon.uf.common.util.ConvertUtil;
/**
* Utility class for working with dataURIs
@@ -45,6 +53,7 @@ import com.raytheon.uf.common.dataplugin.PluginException;
* Apr 18, 2013 1638 mschenke Moved dataURI map generation into here
* from PluginDataObject
* May 15, 2013 1869 bsteffen Move uri map creation from RecordFactory.
+ * May 16, 2013 1869 bsteffen Rewrite dataURI property mappings.
*
*
*
@@ -53,34 +62,208 @@ import com.raytheon.uf.common.dataplugin.PluginException;
*/
public class DataURIUtil {
- /** The singleton instance */
- private static DataURIUtil instance;
+ private static final String PLUGIN_NAME_KEY = "pluginName";
- /** Map of classes and the DataURI annotated fields */
- private Map, Field[]> uriFieldMap;
+ private static final Pattern SEPARATOR_PATTERN = Pattern
+ .compile(DataURI.SEPARATOR);
- /**
- * Constructs the singleton instance
+ private static final Pattern UNDERSCORE_PATTERN = Pattern.compile("_");
+
+ private static final Pattern SPACE_PATTERN = Pattern.compile(" ");
+
+ /*
+ * Compares two fields with the DataURI annotations based off the position.
*/
- private DataURIUtil() {
- uriFieldMap = new HashMap, Field[]>();
- }
+ private static final Comparator dataURIAnnotationComparator = new Comparator() {
- /**
- * Gets the singleton instance
- *
- * @return The singleton instance
- */
- public synchronized static DataURIUtil getInstance() {
- if (instance == null) {
- instance = new DataURIUtil();
+ @Override
+ public int compare(Field f1, Field f2) {
+ int i1 = f1.getAnnotation(DataURI.class).position();
+ int i2 = f2.getAnnotation(DataURI.class).position();
+ return (i1 < i2 ? -1 : (i1 == i2 ? 0 : 1));
}
- return instance;
+
+ };
+
+ private static IPluginClassMapper classMapper;
+
+ /*
+ * Internal cache to avoid constant reflection
+ */
+ private static Map, DataURIFieldAccess[]> uriFieldMap = new ConcurrentHashMap, DataURIFieldAccess[]>();
+
+ /**
+ * The classMapper needs to be injected to allow this class to create new
+ * PDOs based off the pluginName in a dataURI or map.
+ *
+ * @param classMapper
+ */
+ public static void setClassMapper(IPluginClassMapper classMapper) {
+ DataURIUtil.classMapper = classMapper;
}
/**
- * Creates a DataURI map for the specified object based on {@link DataURI}
- * annotations
+ * Build a new dataURI based off the dataURI fields in the PluginDataObject.
+ *
+ * @param pdo
+ * @return
+ * @throws PluginException
+ */
+ public static String createDataURI(PluginDataObject pdo)
+ throws PluginException {
+ StringBuilder uri = new StringBuilder(160);
+ addToDataURI(uri, pdo.getPluginName());
+ for (DataURIFieldAccess access : getAccess(pdo.getClass())) {
+ addToDataURI(uri, access.getFieldValue(pdo));
+ }
+ return SPACE_PATTERN.matcher(uri).replaceAll("_");
+ }
+
+ /**
+ * Create a dataURI based off the dataURI fields in the dataMap.
+ *
+ * @param dataMap
+ * @return
+ * @throws PluginException
+ */
+ public static String createDataURI(Map dataMap)
+ throws PluginException {
+ String pluginName = dataMap.get(PLUGIN_NAME_KEY).toString();
+ StringBuilder uri = new StringBuilder(160);
+ addToDataURI(uri, pluginName);
+ for (DataURIFieldAccess access : getAccess(pluginName)) {
+ addToDataURI(uri, dataMap.get(access.getFieldName()));
+ }
+ return SPACE_PATTERN.matcher(uri).replaceAll("_");
+ }
+
+ /*
+ * Properly formats an arbitrary object into a dataURI.
+ */
+ private static void addToDataURI(StringBuilder uri, Object property) {
+ uri.append("/");
+ if (property == null) {
+ uri.append("null");
+ } else if (property instanceof Calendar) {
+ uri.append(TimeUtil.formatCalendar((Calendar) property));
+ } else {
+ uri.append(SEPARATOR_PATTERN.matcher(String.valueOf(property))
+ .replaceAll("_"));
+ }
+ }
+
+ /**
+ * Parse a dataURI and set the dataURIFields into a dataMap
+ *
+ * @param dataURI
+ * @return
+ * @throws PluginException
+ */
+ public static Map createDataURIMap(String dataURI)
+ throws PluginException {
+ List tokens = tokenizeURI(dataURI);
+ Map dataMap = new HashMap(
+ (int) (tokens.size() / 0.75f + 1), 0.75f);
+ String pluginName = tokens.get(0);
+ tokens = tokens.subList(1, tokens.size());
+ dataMap.put(PLUGIN_NAME_KEY, pluginName);
+ DataURIFieldAccess[] access = getAccess(pluginName);
+ for (int i = 0; i < access.length; i += 1) {
+ dataMap.put(access[i].getFieldName(),
+ access[i].getFieldValue(tokens.get(i)));
+ }
+ return dataMap;
+ }
+
+ /**
+ * Populate a dataMap based off the dataURI fields in the PluginDataObject.
+ *
+ * @param pdo
+ * @return
+ * @throws PluginException
+ */
+ public static Map createDataURIMap(PluginDataObject pdo)
+ throws PluginException {
+ return createDataURIMap((Object) pdo);
+ }
+
+ /**
+ * Create a new PluginDataObject based off the dataURI. THe class of the
+ * result object is based off the pluginName in the dataURI and all fields
+ * present in the DataURI are set into the PDO.
+ *
+ * @param dataURI
+ * @return
+ * @throws PluginException
+ */
+ public static PluginDataObject createPluginDataObject(String dataURI)
+ throws PluginException {
+ PluginDataObject pdo = null;
+ List tokens = tokenizeURI(dataURI);
+ Class clazz = getPluginRecordClass(tokens.get(0));
+ try {
+ pdo = clazz.newInstance();
+ } catch (Exception e) {
+ throw new PluginException(e);
+ }
+ populatePluginDataObject(pdo, tokens);
+ pdo.setDataURI(dataURI);
+ return pdo;
+ }
+
+ /**
+ * Create a new PluginDataObject based off the dataMap. The class of the
+ * result object is based off the pluginName mapping and all dataURI fields
+ * present in the map are set into the PDO.
+ *
+ * @param dataMap
+ * @return
+ * @throws PluginException
+ */
+ public static PluginDataObject createPluginDataObject(
+ Map dataMap) throws PluginException {
+ PluginDataObject pdo = null;
+ Class clazz = getPluginRecordClass(dataMap.get(
+ PLUGIN_NAME_KEY).toString());
+ try {
+ pdo = clazz.newInstance();
+ } catch (Exception e) {
+ throw new PluginException(e);
+ }
+ populatePluginDataObject(pdo, dataMap);
+ return pdo;
+ }
+
+ /**
+ * Populate an existing PluginDataObjects with the DataURI fields from the
+ * dataMap.
+ *
+ * @param pdo
+ * @param dataMap
+ * @throws PluginException
+ */
+ public static void populatePluginDataObject(PluginDataObject pdo,
+ Map dataMap) throws PluginException {
+ pdo.setPluginName(dataMap.get(PLUGIN_NAME_KEY).toString());
+ populateObject(pdo, dataMap);
+ }
+
+ /**
+ * Populate an existing PluginDataObject using fields parsed from the
+ * dataURI.
+ *
+ * @param pdo
+ * @param dataURI
+ * @throws PluginException
+ */
+ public static void populatePluginDataObject(PluginDataObject pdo,
+ String dataURI) throws PluginException {
+ populatePluginDataObject(pdo, tokenizeURI(dataURI));
+ pdo.setDataURI(dataURI);
+ }
+
+ /**
+ * Create a dataURIMap from any object with dataURI annotations.
*
* @param object
* @return
@@ -88,110 +271,208 @@ public class DataURIUtil {
*/
public static Map createDataURIMap(Object object)
throws PluginException {
- try {
- Map map = new HashMap();
- Field[] fields = DataURIUtil.getInstance().getAllDataURIFields(
- object.getClass());
- for (int i = 0; i < fields.length; ++i) {
- String fieldName = PluginDataObject.getDataURIFieldName(
- object.getClass(), i);
- String[] nested = fieldName.split("[.]");
- Object source = object;
- if (nested.length > 0) {
- for (int j = 0; j < nested.length && source != null; ++j) {
- source = PropertyUtils.getProperty(source, nested[j]);
- }
- map.put(fieldName, source);
- }
- }
- return map;
- } catch (Exception e) {
- throw new PluginException("Error constructing dataURI mapping", e);
+ DataURIFieldAccess[] accessArray = getAccess(object.getClass());
+ Map dataMap = new HashMap(
+ (int) (accessArray.length / 0.75f + 2), 0.75f);
+ if (object instanceof PluginDataObject) {
+ dataMap.put(PLUGIN_NAME_KEY,
+ ((PluginDataObject) object).getPluginName());
}
- }
-
- public static Map createDataURIMap(String dataURI, Class clazz)
- throws PluginException {
- Map map = new HashMap();
-
- String[] tokens = dataURI.replaceAll("_", " ").split(DataURI.SEPARATOR);
-
- map.put("pluginName", tokens[1]);
- PluginDataObject obj = null;
- try {
- obj = clazz.newInstance();
-
- for (int i = 2; i < tokens.length; i++) {
- String fieldName = PluginDataObject.getDataURIFieldName(
- obj.getClass(), i - 2);
- if (fieldName == null) {
- continue;
- }
- Object value = obj.getDataURIFieldValue(i - 2, tokens[i]);
- map.put(fieldName, value);
- }
- } catch (Exception e) {
- throw new PluginException("Error constructing dataURI mapping", e);
- }
- return map;
- }
-
- public Field[] getAllDataURIFields(Class> obj) {
- List fields = new ArrayList();
- getAllDataURIFields(obj, fields);
- return fields.toArray(new Field[0]);
- }
-
- private void getAllDataURIFields(Class> obj, List fields) {
- for (Field field : getDataURIFields(obj)) {
- if (field.getAnnotation(DataURI.class).embedded()) {
- getAllDataURIFields(field.getType(), fields);
- } else {
- fields.add(field);
- }
+ for (DataURIFieldAccess access : accessArray) {
+ dataMap.put(access.getFieldName(), access.getFieldValue(object));
}
+ return dataMap;
}
/**
- * Retrieves an ordered listing of all fields annotated as DataURI fields.
+ * Populate an existing object from the dataURI fields in dataMap.
*
- * @param obj
- * The object to examine
- * @return The ordered array of all fields annotated as DataURI fields
+ * @param object
+ * @param dataMap
+ * @throws PluginException
*/
- public Field[] getDataURIFields(Class> obj) {
-
- // Check map first
- if (uriFieldMap.containsKey(obj)) {
- return uriFieldMap.get(obj);
+ public static void populateObject(Object object, Map dataMap)
+ throws PluginException {
+ for (DataURIFieldAccess access : getAccess(object.getClass())) {
+ access.setFieldValue(object, dataMap.get(access.getFieldName()));
}
+ }
- // Iterate through the class hierarchy
+ /*
+ * Populate a PDO with the tokens from a parsed DataURI
+ */
+ private static void populatePluginDataObject(PluginDataObject pdo,
+ List uriTokens) throws PluginException {
+ pdo.setPluginName(uriTokens.get(0));
+ uriTokens = uriTokens.subList(1, uriTokens.size());
+ DataURIFieldAccess[] access = getAccess(pdo.getClass());
+ for (int i = 0; i < access.length; i += 1) {
+ access[i].setFieldValue(pdo,
+ access[i].getFieldValue(uriTokens.get(i)));
+ }
+ }
+
+ /*
+ * Split a URI on the seperator and remove empty first element.
+ */
+ private static List tokenizeURI(String dataURI) {
+ dataURI = UNDERSCORE_PATTERN.matcher(dataURI).replaceAll(" ");
+ String[] tokens = SEPARATOR_PATTERN.split(dataURI);
+ return Arrays.asList(tokens).subList(1, tokens.length);
+ }
+
+ private static DataURIFieldAccess[] getAccess(String pluginName)
+ throws PluginException {
+ return getAccess(getPluginRecordClass(pluginName));
+ }
+
+ private static DataURIFieldAccess[] getAccess(Class> clazz) {
+ DataURIFieldAccess[] result = uriFieldMap.get(clazz);
+ if (result == null) {
+ result = getAccess(clazz, Collections. emptyList())
+ .toArray(new DataURIFieldAccess[0]);
+ uriFieldMap.put(clazz, result);
+ }
+ return result;
+ }
+
+ private static List getAccess(Class> clazz,
+ List parents) {
+ List fields = getOrderedDataURIFields(clazz);
+ List accessors = new ArrayList();
+ for (Field field : fields) {
+ List names = new ArrayList(parents);
+ names.add(field.getName());
+ Class> type = field.getType();
+ if (field.getAnnotation(DataURI.class).embedded()) {
+ accessors.addAll(getAccess(type, names));
+ } else {
+ accessors.add(new DataURIFieldAccess(names, type));
+ }
+ }
+ return accessors;
+ }
+
+ private static List getOrderedDataURIFields(Class> clazz) {
List fields = new ArrayList();
- Class> currentClass = obj;
+ Class> currentClass = clazz;
while (currentClass != null) {
- fields.addAll(Arrays.asList(currentClass.getDeclaredFields()));
+ for (Field field : currentClass.getDeclaredFields()) {
+ if (field.getAnnotation(DataURI.class) != null) {
+ fields.add(field);
+ }
+ }
currentClass = currentClass.getSuperclass();
}
+ Collections.sort(fields, dataURIAnnotationComparator);
+ return fields;
+ }
- // Count the fields annotated with the DataURI annotation
- int fieldCount = 0;
- for (Field field : fields) {
- if (field.getAnnotation(DataURI.class) != null) {
- fieldCount++;
- }
+ public static Class getPluginRecordClass(String pluginName)
+ throws PluginException {
+ if (classMapper == null) {
+ throw new PluginException(
+ "No PluginClassMapper is registered with DataURIUtil.");
}
- // Sort the annotations into an array
- Field[] annotatedFields = new Field[fieldCount];
- for (Field field : fields) {
- DataURI annotation = field.getAnnotation(DataURI.class);
- if (annotation != null) {
- annotatedFields[annotation.position()] = field;
+ return classMapper.getPluginRecordClass(pluginName);
+ }
+
+ /*
+ * Class which remembers the fieldNames and class of a dataURI field to make
+ * parsing faster.
+ */
+ private static class DataURIFieldAccess {
+
+ /**
+ * List of fieldNames, used for finding objects in a PDO, for example
+ * {"location", "longitude"}
+ */
+ private final String[] fieldNames;
+
+ /**
+ * Compiled field names, used as map keys, for example
+ * "location.longitude"
+ */
+ private final String fieldName;
+
+ /**
+ * Class of the oibject that is in the dataURI.
+ */
+ private final Class> fieldClass;
+
+ public DataURIFieldAccess(List fieldNames, Class> fieldClass) {
+ this.fieldNames = fieldNames.toArray(new String[0]);
+ StringBuilder fieldName = new StringBuilder(this.fieldNames[0]);
+ for (int i = 1; i < this.fieldNames.length; i += 1) {
+ fieldName.append(".").append(this.fieldNames[i]);
+ }
+ this.fieldName = fieldName.toString();
+ this.fieldClass = fieldClass;
+ }
+
+ public String getFieldName() {
+ return fieldName;
+ }
+
+ /**
+ * Extract the field value from a PDO.
+ *
+ * @param pdo
+ * @return
+ * @throws PluginException
+ */
+ public Object getFieldValue(Object pdo) throws PluginException {
+ try {
+ Object object = pdo;
+ for (String fieldName : fieldNames) {
+ object = PropertyUtils.getProperty(object, fieldName);
+ if (object == null) {
+ break;
+ }
+ }
+ return object;
+ } catch (Exception e) {
+ throw new PluginException(e);
}
}
- // Put fields in map and return
- uriFieldMap.put(obj, annotatedFields);
- return annotatedFields;
+ /**
+ * Convert the provided string into the correct type for the field.
+ *
+ * @param stringValue
+ * @return
+ * @throws PluginException
+ */
+ public Object getFieldValue(String stringValue) throws PluginException {
+ return ConvertUtil.convertObject(stringValue, fieldClass);
+ }
+
+ /**
+ * Set the fieldValue into the PDO.
+ *
+ * @param pdo
+ * @param fieldValue
+ * @throws PluginException
+ */
+ public void setFieldValue(Object pdo, Object fieldValue)
+ throws PluginException {
+ Object source = pdo;
+ try {
+ for (int i = 0; i < fieldNames.length - 1; i += 1) {
+ Object obj = PropertyUtils.getProperty(source,
+ fieldNames[i]);
+ if (obj == null) {
+ obj = PropertyUtils.getPropertyType(source,
+ fieldNames[i]).newInstance();
+ PropertyUtils.setProperty(source, fieldNames[i], obj);
+ }
+ source = obj;
+ }
+ PropertyUtils.setProperty(source,
+ fieldNames[fieldNames.length - 1], fieldValue);
+ } catch (Exception e) {
+ throw new PluginException(e);
+ }
+ }
}
}
diff --git a/edexOsgi/com.raytheon.uf.edex.database/res/spring/database-common.xml b/edexOsgi/com.raytheon.uf.edex.database/res/spring/database-common.xml
index 5cad91e35b..2ae239d440 100644
--- a/edexOsgi/com.raytheon.uf.edex.database/res/spring/database-common.xml
+++ b/edexOsgi/com.raytheon.uf.edex.database/res/spring/database-common.xml
@@ -45,5 +45,18 @@
+
+
+
+
+
+ com.raytheon.uf.common.dataplugin.annotations.DataURIUtil
+
+
+ setClassMapper
+
+
+
\ No newline at end of file
diff --git a/edexOsgi/com.raytheon.uf.edex.database/src/com/raytheon/uf/edex/database/plugin/PluginDao.java b/edexOsgi/com.raytheon.uf.edex.database/src/com/raytheon/uf/edex/database/plugin/PluginDao.java
index 48163e0892..84f531e8a5 100644
--- a/edexOsgi/com.raytheon.uf.edex.database/src/com/raytheon/uf/edex/database/plugin/PluginDao.java
+++ b/edexOsgi/com.raytheon.uf.edex.database/src/com/raytheon/uf/edex/database/plugin/PluginDao.java
@@ -50,6 +50,7 @@ import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.PluginException;
+import com.raytheon.uf.common.dataplugin.annotations.DataURIUtil;
import com.raytheon.uf.common.dataplugin.persist.DefaultPathProvider;
import com.raytheon.uf.common.dataplugin.persist.IHDFFilePathProvider;
import com.raytheon.uf.common.dataplugin.persist.IPersistable;
@@ -93,20 +94,23 @@ import com.raytheon.uf.edex.database.query.DatabaseQuery;
* SOFTWARE HISTORY
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
- * 2/6/09 1990 bphillip Initial creation
- * 6/29/12 #828 dgilling Force getPurgeRulesForPlugin()
- * to search only COMMON_STATIC.
+ * Feb 06, 2009 1990 bphillip Initial creation
+ * Jun 29, 2012 828 dgilling Force getPurgeRulesForPlugin() to search
+ * only COMMON_STATIC.
* Oct 10, 2012 1261 djohnson Add some generics wildcarding.
- * Jan 14, 2013 1469 bkowal No longer retrieves the hdf5 data directory
- * from the environment.
- * Feb 12, 2013 #1608 randerso Changed to call deleteDatasets
- * Feb 26, 2013 1638 mschenke Moved OGC specific functions to OGC project
+ * Jan 14, 2013 1469 bkowal No longer retrieves the hdf5 data
+ * directory from the environment.
+ * Feb 12, 2013 1608 randerso Changed to call deleteDatasets
+ * Feb 26, 2013 1638 mschenke Moved OGC specific functions to OGC
+ * project
* Mar 27, 2013 1821 bsteffen Remove extra store in persistToHDF5 for
* replace only operations.
- * Apr 04, 2013 djohnson Remove formerly removed methods that won't compile.
+ * Apr 04, 2013 djohnson Remove formerly removed methods that
+ * won't compile.
* Apr 15, 2013 1868 bsteffen Rewrite mergeAll in PluginDao.
* May 07, 2013 1869 bsteffen Remove dataURI column from
* PluginDataObject.
+ * May 16, 2013 1869 bsteffen Rewrite dataURI property mappings.
*
*
*
@@ -365,7 +369,8 @@ public abstract class PluginDao extends CoreDao {
}
}
// This means dataURI is not a column.
- for (Entry uriEntry : pdo.createDataURIMap().entrySet()) {
+ for (Entry uriEntry : DataURIUtil.createDataURIMap(pdo)
+ .entrySet()) {
String key = uriEntry.getKey();
Object value = uriEntry.getValue();
if (key.equals("pluginName")) {
diff --git a/edexOsgi/com.raytheon.uf.edex.database/src/com/raytheon/uf/edex/database/plugin/PluginFactory.java b/edexOsgi/com.raytheon.uf.edex.database/src/com/raytheon/uf/edex/database/plugin/PluginFactory.java
index da8dd4c9c1..fb3024071d 100644
--- a/edexOsgi/com.raytheon.uf.edex.database/src/com/raytheon/uf/edex/database/plugin/PluginFactory.java
+++ b/edexOsgi/com.raytheon.uf.edex.database/src/com/raytheon/uf/edex/database/plugin/PluginFactory.java
@@ -27,6 +27,7 @@ import javax.persistence.Table;
import org.apache.commons.beanutils.ConstructorUtils;
+import com.raytheon.uf.common.dataplugin.IPluginClassMapper;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.PluginException;
import com.raytheon.uf.common.dataplugin.PluginProperties;
@@ -44,17 +45,18 @@ import com.raytheon.uf.edex.core.dataplugin.PluginRegistry;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
- * 06/14/06 garmendariz Initial check-in
- * 05/29/07 312 bphillip Removed unused methods
- * 02/06/09 1990 bphillip Refactored to use spring container
- * 03/20/09 njensen Refactored to use PluginProperties
+ * Jun 14, 2006 garmendariz Initial check-in
+ * May 29, 2007 312 bphillip Removed unused methods
+ * Feb 06, 2009 1990 bphillip Refactored to use spring container
+ * Mar 20, 2009 njensen Refactored to use PluginProperties
+ * May 16, 2013 1869 bsteffen Rewrite dataURI property mappings.
*
*
*
* @author garmendariz
* @version 1.0
*/
-public class PluginFactory {
+public class PluginFactory implements IPluginClassMapper {
/** The instance of the PluginFactory class */
private static final PluginFactory instance = new PluginFactory();
diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.fssobs/src/com/raytheon/uf/edex/plugin/fssobs/FSSObsUtils.java b/edexOsgi/com.raytheon.uf.edex.plugin.fssobs/src/com/raytheon/uf/edex/plugin/fssobs/FSSObsUtils.java
index 98e32b3ce0..93113bf8ed 100644
--- a/edexOsgi/com.raytheon.uf.edex.plugin.fssobs/src/com/raytheon/uf/edex/plugin/fssobs/FSSObsUtils.java
+++ b/edexOsgi/com.raytheon.uf.edex.plugin.fssobs/src/com/raytheon/uf/edex/plugin/fssobs/FSSObsUtils.java
@@ -26,7 +26,6 @@ import java.util.Map.Entry;
import java.util.Scanner;
import com.raytheon.edex.site.SiteUtil;
-import com.raytheon.uf.common.dataplugin.PluginDataObject;
import com.raytheon.uf.common.dataplugin.PluginException;
import com.raytheon.uf.common.dataplugin.annotations.DataURIUtil;
import com.raytheon.uf.common.dataplugin.fssobs.FSSObsRecord;
@@ -40,7 +39,6 @@ import com.raytheon.uf.common.pointdata.PointDataContainer;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
-import com.raytheon.uf.edex.database.plugin.PluginFactory;
import com.raytheon.uf.edex.pointdata.PointDataQuery;
/**
@@ -55,6 +53,7 @@ import com.raytheon.uf.edex.pointdata.PointDataQuery;
* Nov 12, 2010 skorolev Initial creation
* Nov 26, 2012 1297 skorolev Changed ArrayList to List.Clean code
* May 15, 2013 1869 bsteffen Remove DataURI column from ldadmesonet.
+ * May 16, 2013 1869 bsteffen Rewrite dataURI property mappings.
*
*
*
@@ -198,11 +197,8 @@ public class FSSObsUtils {
PointDataQuery request = null;
PointDataContainer result = null;
try {
- Class clazz = PluginFactory.getInstance()
- .getPluginRecordClass(plgn.ldadmesonet.toString());
Map rcMap = RequestConstraint
- .toConstraintMapping(DataURIUtil.createDataURIMap(uri,
- clazz));
+ .toConstraintMapping(DataURIUtil.createDataURIMap(uri));
// Not actually in db
rcMap.remove("pluginName");
request = new PointDataQuery(plgn.ldadmesonet.toString());
diff --git a/ncep/gov.noaa.nws.ncep.edex.common/src/gov/noaa/nws/ncep/edex/common/ncinventory/NcInventoryUpdater.java b/ncep/gov.noaa.nws.ncep.edex.common/src/gov/noaa/nws/ncep/edex/common/ncinventory/NcInventoryUpdater.java
index 234513cc47..c4cfb76200 100644
--- a/ncep/gov.noaa.nws.ncep.edex.common/src/gov/noaa/nws/ncep/edex/common/ncinventory/NcInventoryUpdater.java
+++ b/ncep/gov.noaa.nws.ncep.edex.common/src/gov/noaa/nws/ncep/edex/common/ncinventory/NcInventoryUpdater.java
@@ -20,19 +20,13 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import com.raytheon.edex.uengine.tasks.query.MetadataCatalogQuery;
import com.raytheon.edex.uengine.tasks.query.TableQuery;
import com.raytheon.uf.common.dataplugin.PluginDataObject;
-import com.raytheon.uf.common.dataplugin.PluginProperties;
import com.raytheon.uf.common.dataplugin.annotations.DataURI;
+import com.raytheon.uf.common.dataplugin.annotations.DataURIUtil;
import com.raytheon.uf.common.dataplugin.message.DataURINotificationMessage;
import com.raytheon.uf.common.dataplugin.radar.RadarRecord;
-import com.raytheon.uf.edex.core.dataplugin.PluginRegistry;
import com.raytheon.uf.edex.database.DataAccessLayerException;
-import com.raytheon.uf.edex.database.status.StatusConstants;
/**
*
@@ -42,6 +36,7 @@ import com.raytheon.uf.edex.database.status.StatusConstants;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* 02/20/12 #606 Greg Hull Created
+ * May 16, 2013 1869 bsteffen Rewrite dataURI property mappings.
*
*
*
@@ -84,34 +79,7 @@ public class NcInventoryUpdater {
PluginDataObject pdo = null;
try {
- PluginRegistry reg = PluginRegistry.getInstance();
- PluginProperties props = reg.getRegisteredObject(pluginName);
-
- if( props != null && props.getRecord() != null) {
- pdo = props.getRecord().newInstance();
- }
-
- if( pdo == null ) {
- throw new Exception( "Can't find PDO for plugin.");
- }
-
- for( int i=2 ; i < tokens.length ; i++ ) {
- if( !tokens[i].equals("%") && !tokens[i].trim().isEmpty() ) {
- String fld = PluginDataObject.getDataURIFieldName( pdo.getClass(), i-2 );
-
- if( fld == null ) {
- throw new Exception("Unable to get field name");
- }
-
- Object value = pdo.getDataURIFieldValue( i-2, tokens[i] );
-
- attrsMap.put( fld, value );
- }
- else if( tokens[i].equals("%") ) {
- String fld = PluginDataObject.getDataURIFieldName( pdo.getClass(), i-2 );
- attrsMap.put( fld, "%");
- }
- }
+ attrsMap.putAll(DataURIUtil.createDataURIMap(dataURI));
attrsMap.put( "dataURI", dataURI );