http://git-wip-us.apache.org/repos/asf/oodt/blob/4066b63b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/CompressedObjectCodec.java
----------------------------------------------------------------------
diff --git 
a/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/CompressedObjectCodec.java
 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/CompressedObjectCodec.java
new file mode 100755
index 0000000..2563890
--- /dev/null
+++ 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/CompressedObjectCodec.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.oodt.xmlquery;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InvalidClassException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OptionalDataException;
+import java.io.StreamCorruptedException;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+import org.apache.oodt.commons.io.Base64DecodingInputStream;
+import org.apache.oodt.commons.io.Base64EncodingOutputStream;
+import org.apache.oodt.commons.io.NullOutputStream;
+import org.apache.oodt.commons.util.XML;
+import org.apache.oodt.commons.io.CountingOutputStream;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/** A result encoder/decoder for compressed, serialized objects.
+ *
+ * This codec uses a GZIP compressed serialized object format for objects.
+ *
+ * @author Kelly
+ */
+class CompressedObjectCodec implements Codec {
+       public Node encode(Object object, Document doc) throws DOMException {
+               ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
+               try {
+                       Base64EncodingOutputStream base64 = new 
Base64EncodingOutputStream(byteArray);
+                       GZIPOutputStream gzip = new GZIPOutputStream(base64);
+                       ObjectOutputStream objStream = new 
ObjectOutputStream(gzip);
+                       objStream.writeObject(object);
+                       objStream.close();
+               } catch (IOException ignored) {}
+               Element value = doc.createElement("resultValue");
+               value.appendChild(doc.createCDATASection(byteArray.toString()));
+               return value;
+       }
+
+       public Object decode(Node node) throws ClassNotFoundException, 
InvalidClassException, StreamCorruptedException,
+               OptionalDataException {
+               String encodedValue;
+               if (node.getFirstChild().getNodeType() == 
Node.CDATA_SECTION_NODE) {
+                 encodedValue = node.getFirstChild().getNodeValue();
+               } else {
+                 encodedValue = XML.text(node);
+               }
+               Object rc = null;
+               try {
+                       ByteArrayInputStream byteArray = new 
ByteArrayInputStream(encodedValue.getBytes());
+                       Base64DecodingInputStream base64 = new 
Base64DecodingInputStream(byteArray);
+                       GZIPInputStream gzip = new GZIPInputStream(base64);
+                       ObjectInputStream objStream = new 
ObjectInputStream(gzip);
+                       rc = objStream.readObject();
+                       objStream.close();
+               } catch (InvalidClassException ex) {
+                       throw ex;
+               } catch (StreamCorruptedException ex) {
+                       throw ex;
+               } catch (OptionalDataException ex) {
+                       throw ex;
+               } catch (IOException ignored) {}
+               return rc;
+       }
+
+       public InputStream getInputStream(Object value) throws IOException {
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();
+               ObjectOutputStream oos = new ObjectOutputStream(baos);
+               oos.writeObject(value);
+               oos.close();
+               baos.close();
+               return new ByteArrayInputStream(baos.toByteArray());
+       }
+
+       public long sizeOf(Object obj) {
+               try {
+                       CountingOutputStream c = new CountingOutputStream(new 
NullOutputStream());
+                       ObjectOutputStream stream = new ObjectOutputStream(c);
+                       stream.writeObject(obj);
+                       stream.close();
+                       return c.getBytesWritten();
+               } catch (IOException ex) {
+                       throw new IllegalStateException("I/O exception " + 
ex.getClass().getName() + " can't happen, yet did: "
+                               + ex.getMessage());
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/4066b63b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/CompressedStringCodec.java
----------------------------------------------------------------------
diff --git 
a/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/CompressedStringCodec.java
 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/CompressedStringCodec.java
new file mode 100755
index 0000000..9f7175e
--- /dev/null
+++ 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/CompressedStringCodec.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.oodt.xmlquery;
+
+import org.apache.oodt.commons.io.Base64DecodingInputStream;
+import org.apache.oodt.commons.io.Base64EncodingOutputStream;
+import org.apache.oodt.commons.util.XML;
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+/** A result encoder/decoder for compressed strings.
+ *
+ * This codec uses a GZIP compressed string format for objects.
+ *
+ * @author Kelly
+ */
+class CompressedStringCodec implements Codec {
+
+  public static final int INT = 1024;
+
+  public Node encode(Object object, Document doc) throws DOMException {
+               ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
+               try {
+                       Base64EncodingOutputStream base64 = new 
Base64EncodingOutputStream(byteArray);
+                       GZIPOutputStream gzip = new GZIPOutputStream(base64);
+                       gzip.write(object.toString().getBytes());
+                       gzip.close();
+               } catch (IOException ignored) {}
+               Element value = doc.createElement("resultValue");
+               value.appendChild(doc.createCDATASection(byteArray.toString()));
+               return value;
+       }
+
+       public Object decode(Node node) {
+               String encodedValue;
+               if (node.getFirstChild().getNodeType() == 
Node.CDATA_SECTION_NODE) {
+                 encodedValue = node.getFirstChild().getNodeValue();
+               } else {
+                 encodedValue = XML.text(node);
+               }
+               String rc = null;
+               try {
+                       ByteArrayInputStream byteArray = new 
ByteArrayInputStream(encodedValue.getBytes());
+                       Base64DecodingInputStream base64 = new 
Base64DecodingInputStream(byteArray);
+                       GZIPInputStream gzip = new GZIPInputStream(base64);
+                       StringBuilder b = new StringBuilder();
+                       int numRead;
+                       byte[] buf = new byte[INT];
+                       while ((numRead = gzip.read(buf)) != -1) {
+                         b.append(new String(buf, 0, numRead));
+                       }
+                       gzip.close();
+                       rc = b.toString();
+               } catch (IOException ignored) {}
+               return rc;
+       }
+
+       public InputStream getInputStream(Object value) {
+               return new ByteArrayInputStream(((String) value).getBytes());
+       }
+
+       public long sizeOf(Object obj) {
+               return ((String) obj).getBytes().length;
+       }
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/4066b63b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/Header.java
----------------------------------------------------------------------
diff --git a/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/Header.java 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/Header.java
new file mode 100755
index 0000000..f148425
--- /dev/null
+++ b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/Header.java
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.oodt.xmlquery;
+
+import org.apache.oodt.commons.util.Documentable;
+import org.apache.oodt.commons.util.XML;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/** A single header.
+ *
+ * An object of this class is a header element of a query.
+ *
+ * @author Kelly
+ */
+public class Header implements Serializable, Cloneable, Documentable {
+       /** Create a list of headers from an XML document.
+        *
+        * @param root A <resultHeader> element.
+        * @return A list of <code>Header</code>s.
+        */
+       public static List createHeaders(Node root) {
+               if (!"resultHeader".equals(root.getNodeName())) {
+                 throw new IllegalArgumentException("Expected <resultHeader> 
but got <" + root.getNodeName() + ">");
+               }
+               NodeList children = root.getChildNodes();
+               List rc = new ArrayList();
+               for (int i = 0; i < children.getLength(); ++i){
+                       Node node = children.item(i);
+                       if (node.getNodeType() == Node.ELEMENT_NODE) {
+                               Header header = new Header(node);
+                               rc.add(header);
+                       }
+               }
+               return rc;
+       }
+
+       /** Create a new, blank header.
+        *
+        * This initializes the result with default values for various 
properties.
+        */
+       public Header() {
+               this(/*name*/"UNKNOWN");
+       }
+
+       /** Create a header.
+        *
+        * Here, you specify the header's name only.
+        *
+        * @param name Name of this header.
+        */
+       public Header(String name) {
+               this(name, /*type*/null, /*unit*/null);
+       }
+
+       /** Create a fully specified header.
+        *
+        * @param name Name of this header.
+        * @param type Data type.
+        * @param unit Units.
+        */
+       public Header(String name, String type, String unit) {
+               this.name = name;
+               this.type = type;
+               this.unit = unit;
+       }
+
+       /** Create a header from a DOM node.
+        *
+        * @param node The DOM node, which must be a &lt;headerElement&gt; 
element.
+        */
+       public Header(Node node) {
+               if (!"headerElement".equals(node.getNodeName())) {
+                 throw new IllegalArgumentException("Header must be 
constructed from <headerElement> node, not <"
+                                                                               
         + node.getNodeName() + ">");
+               }
+               NodeList children = node.getChildNodes();
+               for (int i = 0; i < children.getLength(); ++i) {
+                       Node child = children.item(i);
+                       if ("elemName".equals(child.getNodeName())) {
+                         name = XML.unwrappedText(child);
+                       } else if ("elemType".equals(child.getNodeName())) {
+                         type = XML.unwrappedText(child);
+                       } else if ("elemUnit".equals(child.getNodeName())) {
+                         unit = XML.unwrappedText(child);
+                       }
+               }
+       }
+
+       /** Get the name.
+        *
+        * @return The name of the header, suitable for printing in a column 
heading.
+        */
+       public String getName() {
+               return name;
+       }
+
+       /** Get the type of this result.
+        *
+        * @return The type, as in data type.
+        */
+       public String getType() {
+               return type;
+       }
+
+       /** Get the unit.
+        *
+        * @return The units in which the header is presented.
+        */
+       public String getUnit() {
+               return unit;
+       }
+
+       /** Set the name.
+        *
+        * @param name The name of the header, suitable for printing in a 
column heading.
+        */
+       public void setName(String name) {
+               this.name = name;
+       }
+
+       /** Set the type of this result.
+        *
+        * @param type The type, as in data type.
+        */
+       public void setType(String type) {
+               this.type = type;
+       }
+
+       /** Set the unit.
+        *
+        * @param unit The units in which the header is presented.
+        */
+       public void setUnit(String unit) {
+               this.unit = unit;
+       }
+
+       public Node toXML(Document doc) throws DOMException {
+               Element root = doc.createElement("headerElement");
+               XML.add(root, "elemName", getName());
+               XML.addNonNull(root, "elemType", getType());
+               XML.addNonNull(root, "elemUnit", getUnit());
+               return root;
+       }
+
+       public int hashCode() {
+               return name.hashCode();
+       }
+
+       public boolean equals(Object rhs) {
+               if (rhs == this) {
+                 return true;
+               }
+               if (rhs == null || !(rhs instanceof Header)) {
+                 return false;
+               }
+               Header obj = (Header) rhs;
+               return name.equals(obj.name) && ((type == null && obj.type == 
null) || type.equals(obj.type))
+                       && ((unit == null && obj.unit == null) || 
unit.equals(obj.unit));
+       }
+
+       public Object clone() {
+               Object rc;
+               try {
+                       rc = super.clone();
+               } catch (CloneNotSupportedException cantHappen) {
+                       throw new RuntimeException("CloneNotSupportedException 
thrown for class that implements Cloneable: "
+                               + cantHappen.getMessage());
+               }
+               return rc;
+       }
+
+       public String toString() {
+               return getClass().getName() + "[name=" + getName() + ",type=" + 
getType() + ",unit=" + getUnit() + "]";
+       }
+
+       /** Name of the header. */
+       private String name;
+
+       /** Type, as in type of the data. */
+       private String type;
+
+       /** Unit, as in the units of the data type. */
+       private String unit;
+
+        /** Serial version unique ID. */
+        static final long serialVersionUID = -4596588383046581840L;
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/4066b63b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/LargeResult.java
----------------------------------------------------------------------
diff --git 
a/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/LargeResult.java 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/LargeResult.java
new file mode 100644
index 0000000..316650d
--- /dev/null
+++ b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/LargeResult.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.oodt.xmlquery;
+
+import java.util.List;
+import java.util.StringTokenizer;
+import java.io.InputStream;
+import java.io.IOException;
+
+// FIXME: change MIME type application/vnd.jpl.large-product?
+
+/**
+ * A <em>large</em> result is a result for <em>large</em> products.
+ *
+ * What is large?  Some might say large is something that exceeds most other 
things of
+ * like kind in bulk, capacity, quantity, superficial dimensions, or number of 
constituent
+ * units.  Large might be big, great, capacious, extensive.  Large might be 
opposed to
+ * small; as, a large horse; a large house or room; a large lake or pool; a 
large jug or
+ * spoon; a large vineyard; a large army; a large city.  Some might say that 
particularly
+ * if they're named Webster.
+ *
+ * @author Kelly
+ * @version $Revision: 1.2 $
+ */
+public class LargeResult extends Result {
+       /**
+        * Creates a new <code>LargeResult</code> instance.
+        *
+        * @param result a <code>Result</code> value.
+        */
+       public LargeResult(Result result) {
+               super(result.getID(), "application/vnd.jpl.large-product", 
result.getProfileID(), result.getResourceID(),
+                       result.getHeaders(), transformMimeType(result));
+               StringTokenizer st = new StringTokenizer((String) value);
+               st.nextToken();
+               this.size = Long.parseLong(st.nextToken());
+       }
+
+       /**
+        * Creates a new <code>LargeResult</code> instance.
+        *
+        * @param id Result ID.
+        * @param mimeType MIME type.
+        * @param profileID Profile ID.
+        * @param resourceID Resource ID.
+        * @param headers Headers.
+        * @param size Size of the product.
+        */
+       public LargeResult(String id, String mimeType, String profileID, String 
resourceID, List headers, long size) {
+               super(id, "application/vnd.jpl.large-product", profileID, 
resourceID, headers, mimeType + " " + size);
+               this.size = size;
+       }
+
+       /**
+        * Get the size of the product.
+        *
+        * @return Its size.
+        */
+       public final long getSize() {
+               return size;
+       }
+
+       public final String getMimeType() {
+               return new StringTokenizer((String) value).nextToken();
+       }
+
+       /**
+        * Return the result's value.
+        *
+        * @return a String.
+        * @deprecated This method always treats its value as if it were a 
String.  Worse,
+        * for very large results, it cannot contain the entire result in 
memory.  Use
+        * {@link #getInputStream} instead to perform stream processing on 
result data.
+        */
+       public final Object getValue() {
+               Object value = null;
+               InputStream in = null;
+               try {
+                       if (size > Integer.MAX_VALUE) {
+                         throw new IllegalStateException("Cannot use 
getValue() for this product, result is too large; "
+                                                                               
          + "use LargeResult.getInputStream instead");
+                       }
+                       int sizeToRead = (int) size;
+                       byte[] buf = new byte[sizeToRead];
+                       int index = 0;
+                       int num;
+                       in = getInputStream();
+                       while ((num = in.read(buf, index, sizeToRead)) != -1) {
+                               index += num;
+                               sizeToRead -= num;
+                               if (sizeToRead == 0) {
+                                 break;
+                               }
+                       }
+
+                       // OK, this sucks.  Sucks sucks sucks.  Look, getValue 
is not to
+                       // be used anyway.  It sucks.  But dammit, there's some 
annoying
+                       // code over in EDRN which is using it when they should 
be using
+                       // getInputStream.  Basically, if you call this, you're 
a hoser.
+                       // And if you call it and you're not expecting a 
String, you're a
+                       // loser/hoser.  DEPRECATED!
+                       value = new String(buf);
+
+               } catch (IOException ex) {
+                       throw new IllegalStateException("Unexpected 
IOException: " + ex.getMessage());
+               } finally {
+                       if (in != null) {
+                         try {
+                               in.close();
+                         } catch (IOException ignore) {
+                         }
+                       }
+               }
+               return value;
+       }
+
+       /** Size of the product. */
+       private long size;
+
+       /**
+        * Get an input stream that streams the result from the product server.
+        *
+        * @return an <code>InputStream</code> value.
+        * @throws IOException if an error occurs.
+        */
+       public InputStream getInputStream() throws IOException {
+               return new ChunkedProductInputStream(id, retriever, size);
+       }
+
+       /**
+        * Given an existing <code>Result</code> yield its MIME type.
+        *
+        * The existing <code>Result</code> might be a 
<code>LargeResult</code>, in which
+        * case the real MIME type is hidden in the value.  Otherwise, it's 
directly in
+        * the object.
+        *
+        * @param result a <code>Result</code> value.
+        * @return The MIME type.
+        */
+       private static String transformMimeType(Result result) {
+               if 
("application/vnd.jpl.large-product".equals(result.mimeType)) {
+                 return (String) result.value;
+               } else {
+                 return result.mimeType + " 0";
+               }
+       }
+
+       /** Serial version unique ID. */
+       static final long serialVersionUID = -969838775595705444L;
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/4066b63b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/ObjectCodec.java
----------------------------------------------------------------------
diff --git 
a/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/ObjectCodec.java 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/ObjectCodec.java
new file mode 100755
index 0000000..02723d8
--- /dev/null
+++ b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/ObjectCodec.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.oodt.xmlquery;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InvalidClassException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OptionalDataException;
+import java.io.StreamCorruptedException;
+import org.apache.oodt.commons.io.Base64DecodingInputStream;
+import org.apache.oodt.commons.io.Base64EncodingOutputStream;
+import org.apache.oodt.commons.io.NullOutputStream;
+import org.apache.oodt.commons.util.XML;
+import org.apache.oodt.commons.io.CountingOutputStream;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/** A result encoder/decoder for serialized objects.
+ *
+ * This codec uses a serialized object format for objects.
+ *
+ * @author Kelly
+ */
+class ObjectCodec implements Codec {
+       public Node encode(Object object, Document doc) throws DOMException {
+               ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
+               try {
+                       Base64EncodingOutputStream base64 = new 
Base64EncodingOutputStream(byteArray);
+                       ObjectOutputStream objStream = new 
ObjectOutputStream(base64);
+                       objStream.writeObject(object);
+                       objStream.close();
+               } catch (IOException ignored) {}
+               Element value = doc.createElement("resultValue");
+               value.appendChild(doc.createCDATASection(byteArray.toString()));
+               return value;
+       }
+
+       public Object decode(Node node) throws ClassNotFoundException, 
InvalidClassException, StreamCorruptedException,
+               OptionalDataException {
+               String encodedValue;
+               if (node.getFirstChild().getNodeType() == 
Node.CDATA_SECTION_NODE) {
+                 encodedValue = node.getFirstChild().getNodeValue();
+               } else {
+                 encodedValue = XML.text(node);
+               }
+               Object rc = null;
+               try {
+                       ByteArrayInputStream byteArray = new 
ByteArrayInputStream(encodedValue.getBytes());
+                       Base64DecodingInputStream base64 = new 
Base64DecodingInputStream(byteArray);
+                       ObjectInputStream objStream = new 
ObjectInputStream(base64);
+                       rc = objStream.readObject();
+                       objStream.close();
+               } catch (InvalidClassException ex) {
+                       throw ex;
+               } catch (StreamCorruptedException ex) {
+                       throw ex;
+               } catch (OptionalDataException ex) {
+                       throw ex;
+               } catch (IOException ignored) {}
+               return rc;
+       }
+
+       public InputStream getInputStream(Object value) throws IOException {
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();
+               ObjectOutputStream oos = new ObjectOutputStream(baos);
+               oos.writeObject(value);
+               oos.close();
+               baos.close();
+               return new ByteArrayInputStream(baos.toByteArray());
+       }
+
+       public long sizeOf(Object obj) {
+               try {
+                       CountingOutputStream c = new CountingOutputStream(new 
NullOutputStream());
+                       ObjectOutputStream stream = new ObjectOutputStream(c);
+                       stream.writeObject(obj);
+                       stream.close();
+                       return c.getBytesWritten();
+               } catch (IOException ex) {
+                       throw new IllegalStateException("I/O exception " + 
ex.getClass().getName() + " can't happen, yet did: "
+                               + ex.getMessage());
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/4066b63b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/QueryElement.java
----------------------------------------------------------------------
diff --git 
a/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/QueryElement.java 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/QueryElement.java
new file mode 100755
index 0000000..7529f5f
--- /dev/null
+++ b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/QueryElement.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.oodt.xmlquery;
+
+import java.io.*;
+
+import org.apache.oodt.commons.util.*;
+import org.w3c.dom.*;
+
+/** A single query element.
+ *
+ * An object of this class is an element of a query.
+ *
+ * <p>TODO: Consider computing proper mime-type based on class of object being 
inserted as
+ * a value into the result.
+ *
+ * @author Kelly
+ */
+public class QueryElement implements Serializable, Cloneable, Documentable {
+       /** Create a blank query element.
+        */
+       public QueryElement() {
+               this("UNKNOWN", "UNKNOWN");
+       }
+
+       /** Create a query element.
+        *
+        * @param role The role the element plays.
+        * @param value The value of the element.
+        */
+       public QueryElement(String role, String value) {
+               this.role = role;
+               this.value = value;
+       }
+
+       public QueryElement(Node node) {
+               if (!"queryElement".equals(node.getNodeName())) {
+                 throw new IllegalArgumentException("Query element must be 
constructed from <queryElement> node, not <"
+                                                                               
         + node.getNodeName() + ">");
+               }
+               NodeList children = node.getChildNodes();
+               for (int i = 0; i < children.getLength(); ++i) {
+                       Node child = children.item(i);
+                       if ("tokenRole".equals(child.getNodeName())) {
+                         role = XML.unwrappedText(child);
+                       } else if ("tokenValue".equals(child.getNodeName())) {
+                         value = XML.unwrappedText(child);
+                       }
+               }
+       }
+
+       /** Get my role.
+        *
+        * @return The role this element plays.
+        */
+       public String getRole() {
+               return role;
+       }
+
+       /** Get my value.
+        *
+        * @return The value of this element.
+        */
+       public String getValue() {
+               return value;
+       }
+
+       /** Set my role.
+        *
+        * @param role The new role this element plays.
+        */
+       public void setRole(String role) {
+               if (role == null) {
+                 role = "UNKNOWN";
+               }
+               this.role = role;
+       }
+
+       /** Set my value.
+        *
+        * @param value The new value of this element.
+        */
+       public void setValue(String value) {
+               if (value == null) {
+                 value = "UNKNOWN";
+               }
+               this.value = value;
+       }
+
+       public Node toXML(Document doc) throws DOMException {
+               Element root = doc.createElement("queryElement");
+               XML.add(root, "tokenRole", getRole());
+               XML.add(root, "tokenValue", getValue());
+               return root;
+       }
+
+       public boolean equals(Object rhs) {
+               if (rhs == this) {
+                 return true;
+               }
+               if (rhs == null || !(rhs instanceof QueryElement)) {
+                 return false;
+               }
+               QueryElement obj = (QueryElement) rhs;
+               return role.equals(obj.role) && value.equals(obj.value);
+       }
+
+       public int hashCode() {
+               return role.hashCode() ^ value.hashCode();
+       }
+
+       public Object clone() {
+               Object rc = null;
+               try {
+                       rc = super.clone();
+               } catch (CloneNotSupportedException ignored) {}
+               return rc;
+       }
+
+       public String toString() {
+               return getClass().getName() + "[role=" + role + ",value=" + 
value + "]";
+       }
+
+       /** The role I play. */
+       private String role;
+
+       /** The value my role has. */
+       private String value;
+
+        /** Serial version unique ID. */
+        static final long serialVersionUID = -8401434443475540800L;
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/4066b63b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/QueryException.java
----------------------------------------------------------------------
diff --git 
a/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/QueryException.java 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/QueryException.java
new file mode 100755
index 0000000..769e042
--- /dev/null
+++ b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/QueryException.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.oodt.xmlquery;
+
+/** Checked exception to indicate a query fault.
+ *
+ * @author Kelly
+ */
+public class QueryException extends Exception {
+       /** Construct a query exception with no detail message.
+        */
+       public QueryException() {}
+
+       /** Construct a query exception with the given detail message.
+        *
+        * @param msg Detail message.
+        */
+       public QueryException(String msg) {
+               super(msg);
+       }
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/4066b63b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/QueryHeader.java
----------------------------------------------------------------------
diff --git 
a/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/QueryHeader.java 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/QueryHeader.java
new file mode 100755
index 0000000..7e4cb6b
--- /dev/null
+++ b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/QueryHeader.java
@@ -0,0 +1,304 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.oodt.xmlquery;
+
+import org.apache.oodt.commons.util.Documentable;
+import org.apache.oodt.commons.util.XML;
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.io.Serializable;
+import java.net.URI;
+
+/** Header of a query
+ *
+ * @author Kelly
+ */
+public class QueryHeader implements Serializable, Cloneable, Documentable {
+       /** Create a blank query header.
+        */
+       public QueryHeader() {
+               this(/*id*/"UNKNOWN", /*title*/"UNKNOWN", /*desc*/"UNKNOWN", 
/*type*/"QUERY", /*status*/"ACTIVE",
+                       /*security*/"UNKNOWN", /*rev*/"1999-12-12 JSH V1.0 
Under Development", /*datadict*/"UNKNOWN");
+       }
+
+       /** Create a query header with the specified values.
+        *
+        * @param id The identification of this query.
+        * @param title The title of this query.
+        * @param description A string describing this query.
+        * @param type The type of the query, usually QUERY.
+        * @param statusID The status of the query.
+        * @param securityType The type of security to apply to this query.
+        * @param revisionNote A note about the revision history of this query.
+        * @param dataDictID The ID of the data dictionary used by this query.
+        */
+       public QueryHeader(String id, String title, String description, String 
type, String statusID, String securityType,
+               String revisionNote, String dataDictID) {
+               this.id           = id;
+               this.title        = title;
+               this.description  = description;
+               this.type         = type;
+               this.statusID     = statusID;
+               this.securityType = securityType;
+               this.revisionNote = revisionNote;
+               this.dataDictID   = dataDictID;
+       }
+
+       /** Create a query header from an XML node.
+        *
+        * @param node The &lt;queryAttributes&gt; node.
+        */
+       public QueryHeader(Node node) {
+               if (!"queryAttributes".equals(node.getNodeName())) {
+                 throw new IllegalArgumentException("QueryHeader must be 
constructed from <queryAttributes> node, not <"
+                                                                               
         + node.getNodeName() + ">");
+               }
+               NodeList children = node.getChildNodes();
+               for (int i = 0; i < children.getLength(); ++i) {
+                       Node child = children.item(i);
+                       if ("queryId".equals(child.getNodeName())) {
+                         id = XML.unwrappedText(child);
+                       } else if ("queryTitle".equals(child.getNodeName())) {
+                         title = XML.unwrappedText(child);
+                       } else if ("queryDesc".equals(child.getNodeName())) {
+                         description = XML.unwrappedText(child);
+                       } else if ("queryType".equals(child.getNodeName())) {
+                         type = XML.unwrappedText(child);
+                       } else if ("queryStatusId".equals(child.getNodeName())) 
{
+                         statusID = XML.unwrappedText(child);
+                       } else if 
("querySecurityType".equals(child.getNodeName())) {
+                         securityType = XML.unwrappedText(child);
+                       } else if 
("queryRevisionNote".equals(child.getNodeName())) {
+                         revisionNote = XML.unwrappedText(child);
+                       } else if 
("queryDataDictId".equals(child.getNodeName())) {
+                         dataDictID = XML.unwrappedText(child);
+                       }
+               }
+       }
+
+       /** Get the identification of this query.
+        *
+        * @return The identification of this query.
+        */
+       public String getID() {
+               return id;
+       }
+
+       /**
+         * Get the identification of this query as a URI.
+         *
+         * @return an <code>URI</code> value.
+         */
+        public URI getURIID() {
+                return URI.create(id.startsWith("urn")? id : "urn:oodt:query:" 
+ id);
+        }
+
+
+       /** Get the title of this query.
+        *
+        * @return The title of this query.
+        */
+       public String getTitle() {
+               return title;
+       }
+
+       /** Get a string describing this query.
+        *
+        * @return A string describing this query.
+        */
+       public String getDescription() {
+               return description;
+       }
+
+       /** Get the type of the query, usually QUERY.
+        *
+        * @return The type of the query, usually QUERY.
+        */
+       public String getType() {
+               return type;
+       }
+
+       /** Get the status of the query.
+        *
+        * @return The status of the query.
+        */
+       public String getStatusID() {
+               return statusID;
+       }
+
+       /** Get the type of security to apply to this query.
+        *
+        * @return The type of security to apply to this query.
+        */
+       public String getSecurityType() {
+               return securityType;
+       }
+
+       /** Get a note about the revision history of this query.
+        *
+        * @return A note about the revision history of this query.
+        */
+       public String getRevisionNote() {
+               return revisionNote;
+       }
+
+       /** Get the ID of the data dictionary used by this query.
+        *
+        * @return The ID of the data dictionary used by this query.
+        */
+       public String getDataDictID() {
+               return dataDictID;
+       }
+
+       /** Set the identification of this query.
+        *
+        * @param id The identification of this query.
+        */
+       public void setID(String id) {
+               this.id = id;
+       }
+
+       /** Set the title of this query.
+        *
+        * @param title The title of this query.
+        */
+       public void setTitle(String title) {
+               this.title = title;
+       }
+
+       /** Set a string describing this query.
+        *
+        * @param description A string describing this query.
+        */
+       public void setDescription(String description) {
+               this.description = description;
+       }
+
+       /** Set the type of the query, usually QUERY.
+        *
+        * @param type The type of the query, usually QUERY.
+        */
+       public void setType(String type) {
+               this.type = type;
+       }
+
+       /** Set the status of the query.
+        *
+        * @param statusID The status of the query.
+        */
+       public void setStatusID(String statusID) {
+               this.statusID = statusID;
+       }
+
+       /** Set the type of security to apply to this query.
+        *
+        * @param securityType The type of security to apply to this query.
+        */
+       public void setSecurityType(String securityType) {
+               this.securityType = securityType;
+       }
+
+       /** Set a note about the revision history of this query.
+        *
+        * @param revisionNote A note about the revision history of this query.
+        */
+       public void setRevisionNote(String revisionNote) {
+               this.revisionNote = revisionNote;
+       }
+
+       /** Set the ID of the data dictionary used by this query.
+        *
+        * @param dataDictID The ID of the data dictionary used by this query.
+        */
+       public void setDataDictID(String dataDictID) {
+               this.dataDictID = dataDictID;
+       }
+
+       public Node toXML(Document doc) throws DOMException {
+               Element root = doc.createElement("queryAttributes");
+               XML.add(root, "queryId", getID());
+               XML.add(root, "queryTitle", getTitle());
+               XML.add(root, "queryDesc", getDescription());
+               XML.add(root, "queryType", getType());
+               XML.add(root, "queryStatusId", getStatusID());
+               XML.add(root, "querySecurityType", getSecurityType());
+               XML.add(root, "queryRevisionNote", getRevisionNote());
+               XML.add(root, "queryDataDictId", getDataDictID());
+               return root;
+       }
+
+       public int hashCode() {
+               return getID().hashCode();
+       }
+
+       public boolean equals(Object rhs) {
+               if (rhs == this) {
+                 return true;
+               }
+               if (rhs == null || !(rhs instanceof QueryHeader)) {
+                 return false;
+               }
+               QueryHeader obj = (QueryHeader) rhs;
+               return getID().equals(obj.getID());
+       }
+
+       public Object clone() {
+               Object rc = null;
+               try {
+                       rc = super.clone();
+               } catch (CloneNotSupportedException ignored) {}
+               return rc;
+       }
+
+       public String toString() {
+               return getClass().getName() + "[id=" + id + "]";
+       }
+
+       /** The identification of this query. */
+       private String id;
+
+       /** The title of this query. */
+       private String title;
+
+       /** A string describing this query. */
+       private String description;
+
+       /** The type of the query, usually QUERY. */
+       private String type;
+
+       /** The status of the query. */
+       private String statusID;
+
+       /** The type of security to apply to this query. */
+       private String securityType;
+
+       /** A note about the revision history of this query. */
+       private String revisionNote;
+
+       /** The ID of the data dictionary used by this query. */
+       private String dataDictID;
+
+       /** Serial version unique ID. */
+        static final long serialVersionUID = -8601229234696670816L;
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/4066b63b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/QueryResult.java
----------------------------------------------------------------------
diff --git 
a/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/QueryResult.java 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/QueryResult.java
new file mode 100755
index 0000000..81569ba
--- /dev/null
+++ b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/QueryResult.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.oodt.xmlquery;
+
+import org.apache.oodt.commons.util.Documentable;
+import org.apache.oodt.product.Retriever;
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Results of a query.
+ *
+ * @author Kelly
+ */
+public class QueryResult implements Serializable, Cloneable, Documentable {
+       /**
+        * Create empty results.
+        */
+       public QueryResult() {
+               this.list = new ArrayList();
+       }
+
+       /**
+        * Create results from the given list of results.
+        *
+        * @param list List of {@link Result}s.
+        */
+       public QueryResult(List list) {
+               this.list = list;
+       }
+
+       /**
+        * Create results from an XML node.
+        *
+        * @param node The &lt;queryResultSet&gt; node.
+        */
+       public QueryResult(Node node) {
+               if (!"queryResultSet".equals(node.getNodeName())) {
+                 throw new IllegalArgumentException("QueryResult must be 
constructed from <queryResultSet> node, not <"
+                                                                               
         + node.getNodeName() + ">");
+               }
+               list = new ArrayList();
+               NodeList children = node.getChildNodes();
+               for (int i = 0; i < children.getLength(); ++i) {
+                       Node child = children.item(i);
+                       if (child.getNodeType() == Node.ELEMENT_NODE && 
"resultElement".equals(child.getNodeName())) {
+                         list.add(new Result(child));
+                       }
+               }
+       }
+
+       /**
+        * Get the list of results.
+        *
+        * @return A list of {@link Result}s.
+        */
+       public List getList() {
+               return list;
+       }
+
+       /**
+        * Clear out any results.
+        */
+       public void clear() {
+               list.clear();
+       }
+
+       public Node toXML(Document doc) throws DOMException {
+               Element root = doc.createElement("queryResultSet");
+         for (Object aList : list) {
+               Result r = (Result) aList;
+               root.appendChild(r.toXML(doc));
+         }
+               return root;
+       }
+
+       public int hashCode() {
+               return list.hashCode();
+       }
+
+       public boolean equals(Object obj) {
+               if (obj == this) {
+                 return true;
+               }
+               if (obj instanceof QueryResult) {
+                       QueryResult rhs = (QueryResult) obj;
+                       return list.equals(rhs.list);
+               }
+               return false;
+       }
+
+       public Object clone() {
+               try {
+                       return super.clone();
+               } catch (CloneNotSupportedException cantHappen) {
+                       throw new 
IllegalStateException("CloneNotSupportedException happened: " + 
cantHappen.getMessage());
+               }
+       }
+
+       public String toString() {
+               return getClass().getName() + "[list=" + list + "]";
+       }
+
+       public void setRetriever(Retriever retriever) {
+         for (Object aList : list) {
+               Result r = (Result) aList;
+               r.setRetriever(retriever);
+         }
+       }
+
+       public long getSize() {
+               long size = 0;
+         for (Object aList : list) {
+               Result r = (Result) aList;
+               size += r.getSize();
+         }
+               return size;
+       }
+
+       /** List of {@link Result}s. */
+       private List list;
+
+       /** Serial version unique ID. */
+       static final long serialVersionUID = 9156030927051226848L;
+
+
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/4066b63b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/Result.java
----------------------------------------------------------------------
diff --git a/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/Result.java 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/Result.java
new file mode 100755
index 0000000..f893348
--- /dev/null
+++ b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/Result.java
@@ -0,0 +1,447 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.oodt.xmlquery;
+
+import org.apache.oodt.commons.util.Documentable;
+import org.apache.oodt.commons.util.XML;
+import org.apache.oodt.product.Retriever;
+
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+
+/** A single result.
+ *
+ * An object of this class is a result of a query.
+ *
+ * @author Kelly
+ */
+public class Result implements Serializable, Cloneable, Documentable {
+       /** Create a new, blank result.
+        *
+        * This initializes the result with default values for various 
properties.
+        */
+       public Result() {
+               this(/*id*/"UNKNOWN", /*mimeType*/"UNKNOWN", 
/*profileId*/"UNKNOWN", /*resourceId*/"UNKNOWN",
+                       /*resultHeader*/ new ArrayList(), /*value*/"");
+       }
+
+       /** Create a result.
+        *
+        * Here, you specify the result's ID and value only.
+        *
+        * @param id Identification of this result.
+        * @param value The result.
+        */
+       public Result(String id, Object value) {
+               this(id, /*mimeType*/"UNKNOWN", /*profileId*/"UNKNOWN", 
/*resourceId*/"UNKNOWN",
+                       /*resultHeader*/ new ArrayList(), value);
+       }
+
+       /**
+        * Create a more fully specified result that's not classified and lasts 
forever.
+        *
+        * @param id Identification of this result.
+        * @param mimeType MIME Type.
+        * @param profileID ID of the resource profile where this result 
originated.
+        * @param resourceID ID of the resource where this result originated.
+        * @param headers A header elements, describing the result.
+        * @param value The result.
+        */
+       public Result(String id, String mimeType, String profileID, String 
resourceID, List headers, Object value) {
+               this(id, mimeType, profileID, resourceID, headers, value, 
/*classified*/false, /*validity*/INFINITE);
+       }
+
+       /**
+        * Create a fully specified result.
+        *
+        * @param id Identification of this result.
+        * @param mimeType MIME Type.
+        * @param profileID ID of the resource profile where this result 
originated.
+        * @param resourceID ID of the resource where this result originated.
+        * @param headers A header elements, describing the result.
+        * @param value The result.
+        * @param classified True if this result is secret, false otherwise.
+        * @param validity Time for how long this product is valid in 
milliseconds or {@link #INFINITE}.
+        */
+       public Result(String id, String mimeType, String profileID, String 
resourceID, List headers, Object value,
+               boolean classified, long validity) {
+               if (validity < 0 && validity != INFINITE) {
+                 throw new IllegalArgumentException("Validity must be a 
nonnegative time in milliseconds or "
+                                                                               
         + " Result.INFINITE to indicate no expiration");
+               }
+               if (!codecs.containsKey(mimeType)) {
+                 throw new IllegalArgumentException("MIME type \"" + mimeType 
+ "\" unknown");
+               }
+         for (Object header : headers) {
+               if (!(header instanceof Header)) {
+                 throw new IllegalArgumentException("List of headers doesn't 
contain Header object");
+               }
+         }
+
+               this.id         = id;
+               this.mimeType   = mimeType;
+               this.profileID  = profileID;
+               this.resourceID = resourceID;
+               this.headers    = headers;
+               this.value      = value;
+               this.classified = classified;
+               this.validity   = validity;
+       }
+
+       /** Create a result from a DOM node.
+        *
+        * @param node The DOM node, which must be a &lt;resultElement&gt; 
element.
+        */
+       public Result(Node node) {
+               if (!"resultElement".equals(node.getNodeName())) {
+                 throw new IllegalArgumentException("Result must be 
constructed from <resultElement> node, not <"
+                                                                               
         + node.getNodeName() + ">");
+               }
+               Element rootElement = (Element) node;
+               classified = 
"true".equals(rootElement.getAttribute("classified"));
+               validity = Long.parseLong(rootElement.getAttribute("validity"));
+               NodeList children = node.getChildNodes();
+               String encodedValue = null;
+               for (int i = 0; i < children.getLength(); ++i) {
+                       Node child = children.item(i);
+                       if ("resultId".equals(child.getNodeName())) {
+                         id = XML.unwrappedText(child);
+                       } else if 
("resultMimeType".equals(child.getNodeName())) {
+                         mimeType = XML.unwrappedText(child);
+                       } else if ("profId".equals(child.getNodeName())) {
+                         profileID = XML.unwrappedText(child);
+                       } else if ("identifier".equals(child.getNodeName())) {
+                         resourceID = XML.unwrappedText(child);
+                       } else if ("resultHeader".equals(child.getNodeName())) {
+                         headers = Header.createHeaders(child);
+                       } else if ("resultValue".equals(child.getNodeName())) {
+                               Codec codec = (Codec) codecs.get(mimeType);
+                               if (codec == null) {
+                                 throw new IllegalArgumentException("Unkown 
MIME type \"" + mimeType
+                                                                               
                         + "\" in <resultElement>'s <resultMimeType>");
+                               }
+                               try {
+                                       value = codec.decode(child);
+                               } catch (RuntimeException ex) {
+                                       throw ex;
+                               } catch (Exception ex) {
+                                       throw new IllegalArgumentException("Bad 
encoding of " + mimeType + " object");
+                               }
+                       }
+               }
+       }
+
+       /** Get the result ID.
+        *
+        * @return The identification of this result.
+        */
+       public String getID() {
+               return id;
+       }
+
+       public URI getURIID() {
+               return URI.create(id.startsWith("urn")? id : 
"urn:eda:result:unspec:" + id);
+       }
+
+       /** Get the MIME type of this result.
+        *
+        * @return The MIME type.
+        */
+       public String getMimeType() {
+               return mimeType;
+       }
+
+       /** Get the profile ID.
+        *
+        * @return The ID of the resource profile where this result originated.
+        */
+       public String getProfileID() {
+               return profileID;
+       }
+
+       /** Get the resource ID.
+        *
+        * @return The ID of the resource where this result originated.
+        */
+       public String getResourceID() {
+               return resourceID;
+       }
+
+       /** Get the headers.
+        *
+        * @return A list of {@link Header}s describing the result.
+        */
+       public List getHeaders() {
+               return headers;
+       }
+
+       /** Get the result's value.
+        *
+        * @return The result instance.
+        * @deprecated This method requires the caller to know the return type 
and to
+        * downcast to it; further, the result may be too large to contain in 
memory.  Use
+        * {@link #getInputStream} instead to perform stream processing on 
product data.
+        */
+       public Object getValue() {
+               return value;
+       }
+
+       /** Set the result ID.
+        *
+        * @param id The identification of this result.
+        */
+       public void setID(String id) {
+               this.id = id;
+       }
+
+       /** Set the MIME type of this result.
+        *
+        * @param mimeType The MIME type.
+        */
+       public void setMimeType(String mimeType) {
+               this.mimeType = mimeType;
+       }
+
+       /** Set the profile ID.
+        *
+        * @param profileID The ID of the resource profile where this result 
originated.
+        */
+       public void setProfileID(String profileID) {
+               this.profileID = profileID;
+       }
+
+       /** Set the resource ID.
+        *
+        * @param resourceID The ID of the resource where this result 
originated.
+        */
+       public void setResourceID(String resourceID) {
+               this.resourceID = resourceID;
+       }
+
+       /** Set the result's value.
+        *
+        * @param value The result instance.
+        */
+       public void setValue(Object value) {
+               this.value = value;
+       }
+
+       /**
+        * Get the size of this product.
+        *
+        * @return Size in bytes.
+        */
+       public long getSize() {
+               Codec codec = (Codec) codecs.get(mimeType);
+               if (codec == null) {
+                 throw new IllegalStateException("No codec available for 
supposedly valid MIME type \""
+                                                                               
  + mimeType + "\"");
+               }
+               return codec.sizeOf(value);
+       }
+
+       public Node toXML(Document doc) throws DOMException {
+               Element root = doc.createElement("resultElement");
+               root.setAttribute("classified", String.valueOf(classified));
+               root.setAttribute("validity", String.valueOf(validity));
+               XML.add(root, "resultId", id);
+               XML.add(root, "resultMimeType", mimeType);
+               XML.add(root, "profId", profileID);
+               XML.add(root, "identifier", resourceID);
+               Element resultHeader = doc.createElement("resultHeader");
+               root.appendChild(resultHeader);
+         for (Object header1 : headers) {
+               Header header = (Header) header1;
+               resultHeader.appendChild(header.toXML(doc));
+         }
+               Codec codec = (Codec) codecs.get(mimeType);
+               if (codec == null) {
+                 throw new IllegalStateException("No codec available for 
supposedly valid MIME type \""
+                                                                               
  + mimeType + "\"");
+               }
+               root.appendChild(codec.encode(value, doc));
+               return root;
+       }
+
+       /**
+        * Get an input stream version of the result's value.
+        *
+        * @return an <code>InputStream</code> value.
+        * @throws IOException if an error occurs.
+        */
+       public InputStream getInputStream() throws IOException {
+               Codec codec = (Codec) codecs.get(mimeType);
+               if (codec == null) {
+                 throw new IllegalStateException("No codec available for 
allegedly valid MIME type \""
+                                                                               
  + mimeType + "\"");
+               }
+               return codec.getInputStream(value);
+       }
+
+       /**
+        * Is this result classified?
+        *
+        * @return a boolean value.
+        */
+       public boolean isClassified() {
+               return classified;
+       }
+
+       /**
+        * Set whether this result is classified.
+        *
+        * @param classified a boolean value.
+        */
+       public void setClassified(boolean classified) {
+               this.classified = classified;
+       }
+
+       /**
+        * Get how long this product is valid.
+        *
+        * @return Time in milliseconds or {@link #INFINITE}.
+        */
+       public long getValidity() {
+               return validity;
+       }
+
+       /**
+        * Set the time this product is valid.
+        *
+        * @param validity Time in milliseconds or {@link #INFINITE}.
+        */
+       public void setValidity(long validity) {
+               this.validity = validity;
+       }
+
+       public int hashCode() {
+               return id.hashCode() ^ mimeType.hashCode() ^ 
profileID.hashCode() ^ resourceID.hashCode() ^ headers.hashCode()
+                       ^ value.hashCode();
+       }
+
+       public boolean equals(Object rhs) {
+               if (rhs == this) {
+                 return true;
+               }
+               if (rhs == null || !(rhs instanceof Result)) {
+                 return false;
+               }
+               Result obj = (Result) rhs;
+               return id.equals(obj.id) && mimeType.equals(obj.mimeType) && 
profileID.equals(obj.profileID)
+                       && resourceID.equals(obj.resourceID) && 
headers.equals(obj.headers) && value.equals(obj.value);
+       }
+
+       public Object clone() {
+               Object rc;
+               try {
+                       rc = super.clone();
+               } catch (CloneNotSupportedException cantHappen) {
+                       throw new RuntimeException("CloneNotSupportedException 
thrown for class that implements Cloneable: "
+                               + cantHappen.getMessage());
+               }
+               return rc;
+       }
+
+       public void setRetriever(Retriever retriever) {
+               if (retriever == null) {
+                 throw new IllegalArgumentException("retriever must be 
non-null");
+               }
+               if (this.retriever == null) {
+                 this.retriever = retriever;
+               }
+       }
+
+       public String toString() {
+               return getClass().getName() + "[id=" + getID() + ",mimeType=" + 
getMimeType() + ",profileID=" + getProfileID()
+                       + ",resourceID=" + getResourceID() + ",value=" + 
getValue() + "]";
+       }
+
+       /** The identification of this result. */
+       protected String id;
+
+       /** The MIME type. */
+       protected String mimeType;
+
+       /** The ID of the resource profile where this result originated. */
+       private String profileID;
+
+       /** The ID of the resource where this result originated. */
+       private String resourceID;
+
+       /** The headers describing the result. */
+       private List headers;
+
+       /** The result instance. */
+       protected Object value;
+
+       /** True if this product is classified. */
+       private boolean classified;
+
+       /** For how long the product's good. */
+       private long validity;
+
+       /** Mapping of MIME type to codec. */
+       protected static Map codecs;
+
+       /** Object to retrieve this product's data. */
+       protected transient Retriever retriever;
+
+       /** Initialize the set of valid MIME types. */
+       static {
+               codecs = new ConcurrentHashMap();
+               try {
+                       java.io.InputStream inp = 
Result.class.getResourceAsStream("mime.properties");
+                       BufferedInputStream in = new BufferedInputStream(inp);
+                       Properties props = new Properties();
+                       props.load(in);
+                       in.close();
+                 for (Map.Entry<Object, Object> objectObjectEntry : 
props.entrySet()) {
+                       Map.Entry entry = (Map.Entry) objectObjectEntry;
+                       codecs.put(entry.getKey(), 
CodecFactory.createCodec((String) entry.getValue()));
+                 }
+               } catch (IOException ex) {
+                       System.err.println("I/O exception WHILE reading 
mime.properties: " + ex.getMessage());
+                       ex.printStackTrace();
+                       System.err.println("No valid MIME types will be 
recognized by class Result");
+               }
+
+               // Add our own special MIME type:
+               
codecs.put("UNKNOWN",CodecFactory.createCodec("org.apache.oodt.xmlquery.UnsupportedMimeTypeCodec"));
+       }
+
+       /** Serial version unique ID. */
+       static final long serialVersionUID = 9169143944191239575L;
+
+       /** Sentinel value for validity that indicates a product never expires. 
*/
+       public static final long INFINITE = -1;
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/4066b63b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/Results.java
----------------------------------------------------------------------
diff --git a/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/Results.java 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/Results.java
new file mode 100755
index 0000000..cfd8c9a
--- /dev/null
+++ b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/Results.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.oodt.xmlquery;
+
+import java.util.Vector;
+
+/************************************************************************
+**
+** Results
+**
+** This will manage a list of results
+**
+*************************************************************************/
+
+public class Results
+{
+    Vector v;
+
+    public Results()
+    {
+
+        v = new Vector();
+    }
+
+    public synchronized void addItem(Object o)
+    {
+        v.addElement(o);
+    }
+
+    public synchronized void removeItem(int i)
+    {
+        v.removeElementAt(i);
+    }
+
+    public synchronized int getCount()
+    {
+        return(v.size());
+    }
+
+    public synchronized Object getItem(int i)
+    {
+        return((Object) v.elementAt(i));
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/oodt/blob/4066b63b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/Statistic.java
----------------------------------------------------------------------
diff --git 
a/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/Statistic.java 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/Statistic.java
new file mode 100755
index 0000000..2b4dae0
--- /dev/null
+++ b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/Statistic.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ *     EDM Statistic Class
+ */
+
+package org.apache.oodt.xmlquery;
+
+import org.apache.oodt.commons.util.XML;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * EDM Statisti class. 
+ */
+public class Statistic implements java.io.Serializable, Cloneable 
+{
+        /** Serial version unique ID. */
+        static final long serialVersionUID = 8611279755682736062L;
+       
+        /** URL. */
+       private String url;
+
+       /** Time. */
+       private long time;
+
+       public Statistic()
+        {
+               url = "UNKNOWN";
+               time = 0;
+       }
+
+       /** Constructor.
+        *
+        * @param url  The server's URL. 
+        * @param time The search time used by the server indicted by url.
+         */
+       public Statistic(String url, long time) 
+       {
+               this.url=url;
+               this.time= time;
+       }
+
+         /**
+         * Instantiates an Statistic instance from an Statistic structure in 
DOM node format.
+         *
+         * @param root  The DOM node.
+         */
+       public Statistic(Node root)
+       {
+               Node node;
+               String nodeName;
+
+               for (node = root.getFirstChild();
+                       node != null; node = node.getNextSibling())
+               {
+                       if (node instanceof Element)
+                       {
+                               nodeName = node.getNodeName();
+                               if (nodeName.compareTo("url") == 0) {
+                                                         url = 
XML.unwrappedText(node);
+                                                       } else
+                               if (nodeName.compareTo("time") == 0) {
+                                                         time = 
Long.parseLong(XML.unwrappedText(node));
+                                                       }
+                       }
+               }
+       }
+
+        /**
+         *  doc The org.w3c.dom.Document object.
+         */
+       public synchronized Node toXML(Document doc) throws DOMException
+       {
+                Element root = doc.createElement("statistic");
+                XML.add(root, "url", url);
+                XML.add(root, "time", ""+time);
+                return root;
+        }
+
+
+        /**
+         * Gets the URL string.
+         *
+         * @return The URL string.
+         */
+       public synchronized String getURL () {
+               return url;
+       }
+
+
+        /**
+         * Gets the search time
+         *
+         * @return the time
+         */
+       public synchronized long getTime()
+       {
+               return time;
+       }
+       
+       /**
+         * Sets the search time         */              
+        public synchronized void setTime(long time)
+        {
+                this.time= time;
+        }
+
+       public static void main(String[] args) throws Exception
+       {
+               Statistic sta = new Statistic("DDM", 1200);     // test 
constructor 2
+               System.err.println("Profile Server:"+sta.getURL());
+               System.err.println("Search time:"+sta.getTime());
+               Statistic sta1 = new Statistic();               // test 
construct 1
+               System.err.println("Profile Server:"+sta1.getURL());
+                System.err.println("Search time:"+sta1.getTime());
+               
+               // create a document
+               Document doc = XML.createDocument();
+                Element StatisticNode = doc.createElement("Statistic");
+                doc.appendChild(StatisticNode);
+               XML.add(StatisticNode, "url", "DMIE");
+               XML.add(StatisticNode, "time", ""+2000);
+
+
+               Element root = doc.getDocumentElement();        //test 
constructor 3
+               Statistic sta2 = new Statistic(root);   
+               System.err.println("Profile Server:"+sta2.getURL());
+                System.err.println("Search time:"+sta2.getTime());
+
+
+               //test toXML()
+               Node root1 = sta2.toXML(doc);
+               Statistic sta3 = new Statistic(root1);
+                System.err.println("Profile Server:"+sta3.getURL());
+                System.err.println("Search time:"+sta3.getTime());
+       }
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/4066b63b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/StringCodec.java
----------------------------------------------------------------------
diff --git 
a/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/StringCodec.java 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/StringCodec.java
new file mode 100755
index 0000000..cc429d3
--- /dev/null
+++ b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/StringCodec.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.oodt.xmlquery;
+
+import java.io.*;
+
+import org.apache.oodt.commons.util.*;
+import org.w3c.dom.*;
+
+/** A result encoder/decoder for strings.
+ *
+ * This codec uses a string format for objects.
+ *
+ * @author Kelly
+ */
+class StringCodec implements Codec {
+       public Node encode(Object object, Document doc) throws DOMException {
+               Element value = doc.createElement("resultValue");
+               value.setAttribute("xml:space", "preserve");
+               value.appendChild(doc.createTextNode(object.toString()));
+               return value;
+       }
+
+       public Object decode(Node node) {
+               return XML.text(node);
+       }
+
+       public InputStream getInputStream(Object value) throws IOException {
+               return new ByteArrayInputStream(((String) value).getBytes());
+       }
+
+       public long sizeOf(Object object) {
+               return ((String) object).getBytes().length;
+       }
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/4066b63b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/UnsupportedMimeTypeCodec.java
----------------------------------------------------------------------
diff --git 
a/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/UnsupportedMimeTypeCodec.java
 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/UnsupportedMimeTypeCodec.java
new file mode 100755
index 0000000..9afe8e4
--- /dev/null
+++ 
b/webapp/fmprod/src/main/java/org/apache/oodt/xmlquery/UnsupportedMimeTypeCodec.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.oodt.xmlquery;
+
+import java.io.*;
+import org.w3c.dom.*;
+
+/** A result encoder/decoder for unsupported MIME types.
+ *
+ * This codec throws <code>UnsupportedOperationException</code>s on any 
encoding or
+ * decoding attempt.
+ *
+ * @author Kelly
+ */
+class UnsupportedMimeTypeCodec implements Codec {
+       public Node encode(Object object, Document doc) {
+               throw new UnsupportedOperationException("MIME type not 
supported for encoding");
+       }
+       public Object decode(Node node) {
+               throw new UnsupportedOperationException("MIME type not 
supported for decoding");
+       }
+       public long sizeOf(Object object) {
+               throw new UnsupportedOperationException("MIME type not 
supported for sizing");
+       }
+       public InputStream getInputStream(Object object) {
+               throw new UnsupportedOperationException("MIME type not 
supported for streaming");
+       }
+}

Reply via email to