You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by ma...@apache.org on 2017/06/28 05:57:32 UTC

[19/25] incubator-atlas git commit: ATLAS-1898: initial commit of ODF

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-api/src/main/java/org/apache/atlas/odf/json/AnnotationDeserializer.java
----------------------------------------------------------------------
diff --git a/odf/odf-api/src/main/java/org/apache/atlas/odf/json/AnnotationDeserializer.java b/odf/odf-api/src/main/java/org/apache/atlas/odf/json/AnnotationDeserializer.java
new file mode 100755
index 0000000..6ea9c97
--- /dev/null
+++ b/odf/odf-api/src/main/java/org/apache/atlas/odf/json/AnnotationDeserializer.java
@@ -0,0 +1,165 @@
+/**
+ * Licensed 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.atlas.odf.json;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.apache.atlas.odf.api.metadata.models.Annotation;
+import org.apache.atlas.odf.api.metadata.models.ClassificationAnnotation;
+import org.apache.atlas.odf.api.metadata.models.ProfilingAnnotation;
+import org.apache.atlas.odf.api.metadata.models.RelationshipAnnotation;
+
+/**
+ * The Jackson deserializer for Annotation objects
+ * 
+ *
+ */
+public class AnnotationDeserializer extends StdDeserializer<Annotation> {
+
+	private static final long serialVersionUID = -3143233438847937374L;
+	
+	Logger logger = Logger.getLogger(AnnotationDeserializer.class.getName());
+	
+	public AnnotationDeserializer() {
+		super(Annotation.class);
+	}
+
+	ClassLoader getClassLoader() {
+		return this.getClass().getClassLoader();
+	}
+	
+	@Override
+	public Annotation deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+		ObjectMapper jpom = ((ObjectMapper) jp.getCodec());
+		ObjectNode tree = jpom.readTree(jp);
+		String jsonString = tree.toString();
+		Annotation result = null;
+
+		Class<? extends Annotation> javaClass = null;
+		JsonNode javaClassNode = tree.get("javaClass");
+		if (javaClassNode == null) {
+			throw new IOException("Can not deserialize object since the javaClass attribute is missing: " + jsonString);
+		}
+		JsonNode jsonPropertiesNode = tree.get("jsonProperties");
+		String javaClassName = javaClassNode.asText();
+		if (javaClassName.equals(ProfilingAnnotation.class.getName())) {
+			javaClass = ProfilingAnnotation.class;
+		}
+		else if (javaClassName.equals(ClassificationAnnotation.class.getName())) {
+			javaClass = ClassificationAnnotation.class;
+		}
+		else if (javaClassName.equals(RelationshipAnnotation.class.getName())) {
+			javaClass = RelationshipAnnotation.class;
+		}
+		else {
+			try {
+				javaClass = (Class<? extends Annotation>) this.getClassLoader().loadClass(javaClassName);
+				if (jsonPropertiesNode != null && !jsonPropertiesNode.isNull()) { // unfold jsonProperties in case of specific annotations
+					JsonNode jsonPropertiesNodeUnfolded = null;
+					if (jsonPropertiesNode.isTextual()) {
+						jsonPropertiesNodeUnfolded = jpom.readTree(jsonPropertiesNode.asText());					
+					}
+					else {
+						jsonPropertiesNodeUnfolded = jsonPropertiesNode; 
+					}
+					JsonNode newJsonPropertiesNode = (JsonNode)jp.getCodec().createObjectNode();    // initialize new jsonProperties node
+					Field classFields[] = javaClass.getDeclaredFields();
+					HashSet<String> classFieldSet = new HashSet<String>();
+					for (Field f: classFields) {
+						f.setAccessible(true);
+						String fieldName = f.getName();
+						classFieldSet.add(fieldName);
+					}
+					Iterator<Entry<String,JsonNode>> jsonPropertiesFields = jsonPropertiesNodeUnfolded.fields();
+					while (jsonPropertiesFields.hasNext()) { 
+						Entry<String,JsonNode> field = jsonPropertiesFields.next();
+						String fieldName = field.getKey();
+						if (JSONUtils.annotationFields.contains(fieldName)) {
+							throw new IOException("Name conflict: Field name in jsonProperties matches predefined field [" + fieldName + "]");
+						}
+						JsonNode fieldValue = field.getValue();
+						if (classFieldSet.contains(fieldName)) {
+							tree.set(fieldName, fieldValue);							
+						}
+						else {
+							((ObjectNode)newJsonPropertiesNode).set(fieldName, field.getValue());							
+						}
+					}
+					tree.put("jsonProperties", newJsonPropertiesNode.textValue());
+				}
+			} catch (ClassNotFoundException exc) {
+				String msg = MessageFormat.format("Java class ''{0}'' could not be deserialized automatically (probably because it is not on the classpath)", javaClassName);
+				logger.warning(msg);
+				logger.log(Level.FINE, msg, exc);
+			}
+			if (javaClass == null) {
+				if (tree.get("profiledObject") != null) {   // class not found -> create as instance of corresponding 'unknown' types
+					javaClass = ProfilingAnnotation.class;
+				}
+				else if (tree.get("classifiedObject") != null) {
+					javaClass = ClassificationAnnotation.class;
+				}
+				else if (tree.get("relatedObjects") != null) {
+					javaClass = RelationshipAnnotation.class;
+				}
+				else { // malformed annotation
+					javaClass = Annotation.class;
+				}
+				if (jsonPropertiesNode == null) {
+					jsonPropertiesNode = (JsonNode)jp.getCodec().createObjectNode(); // initialize if not already present
+				}
+				Iterator<Entry<String,JsonNode>> fields = tree.fields();
+				ArrayList<String> fieldsToRemove = new ArrayList<String>();
+				try {
+					while (fields.hasNext()) {     // move all fields not present in the predefined annotation types
+						Entry<String,JsonNode> field = fields.next();   // to the string valued jsonProperties attribute
+						String fieldName = field.getKey();
+						if (!JSONUtils.annotationFields.contains(fieldName)) {
+							((ObjectNode)jsonPropertiesNode).set(fieldName, field.getValue());
+							fieldsToRemove.add(fieldName);
+						}
+					}
+					String jsonProperties = (jsonPropertiesNode.isTextual()) ? jsonPropertiesNode.textValue() : jsonPropertiesNode.toString();
+					tree.put("jsonProperties", jsonProperties); 
+					for (String fieldToRemove:fieldsToRemove) {  // remove fields not present in the predefined annotation types
+						tree.remove(fieldToRemove);
+					}
+				}
+				catch (Exception e) {
+					throw new IOException(e);
+				}
+			}
+			jsonString = tree.toString();				
+		}
+		result = jpom.readValue(jsonString, javaClass);
+		logger.log(Level.FINEST, "Annotation created. Original: {0}, deserialized annotation: {1}", new Object[]{ jsonString, JSONUtils.lazyJSONSerializer(result)});
+		return result;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-api/src/main/java/org/apache/atlas/odf/json/AnnotationSerializer.java
----------------------------------------------------------------------
diff --git a/odf/odf-api/src/main/java/org/apache/atlas/odf/json/AnnotationSerializer.java b/odf/odf-api/src/main/java/org/apache/atlas/odf/json/AnnotationSerializer.java
new file mode 100755
index 0000000..6fcc28e
--- /dev/null
+++ b/odf/odf-api/src/main/java/org/apache/atlas/odf/json/AnnotationSerializer.java
@@ -0,0 +1,121 @@
+/**
+ * Licensed 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.atlas.odf.json;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.logging.Logger;
+
+import org.apache.atlas.odf.api.metadata.models.Annotation;
+import org.apache.wink.json4j.JSONException;
+import org.apache.wink.json4j.JSONObject;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+/**
+ * The Jackson serializer for Annotation objects
+ * 
+ *
+ */
+public class AnnotationSerializer extends StdSerializer<Annotation> {
+
+	public AnnotationSerializer() {
+		this(null);
+	}
+	
+	public AnnotationSerializer(Class<Annotation> t) {
+		super(t);
+	}
+	
+	Logger logger = Logger.getLogger(AnnotationSerializer.class.getName());
+
+	ClassLoader getClassLoader() {
+		return this.getClass().getClassLoader();
+	}
+	
+	// In the following jsonProperties is either already pre-populated (because we are serializing an instance of ProfilingAnnotation, ....
+	// or it is created from all attributes not present in ProfilingAnnotation, or its ancestors (e.g. serializing an instance of ColumnAnalysisColumnAnntation)
+	// in the latter case jsonProperties is expected to be null
+	
+	@Override
+	public void serialize(Annotation annot, JsonGenerator jg, SerializerProvider sp) throws IOException, JsonProcessingException {
+		jg.writeStartObject();
+		Class<?> cl = annot.getClass();
+		class JSONPropField {
+			String name;
+			Object value;
+			JSONPropField(String name, Object value) {this.name = name; this.value = value;}
+		}
+		ArrayList<JSONPropField> jsonPropFields = null;
+		String jsonPropertiesValue = null;
+		while (cl != Object.class) {   // process class hierarchy up to and including MetaDataObject.class
+			Field fields[] = cl.getDeclaredFields();
+			for (Field f: fields) {
+				f.setAccessible(true);
+				String fieldName = f.getName();
+				try {
+					Object fieldValue = f.get(annot);
+					if (fieldName.equals("jsonProperties")) {
+						jsonPropertiesValue = (String)fieldValue;
+					}
+					else if (JSONUtils.annotationFields.contains(fieldName)) {
+						jg.writeFieldName(fieldName);
+						jg.writeObject(fieldValue);							
+					}
+					else {
+						if (jsonPropFields == null) jsonPropFields = new ArrayList<JSONPropField>();
+						jsonPropFields.add(new JSONPropField(fieldName, fieldValue));
+					}
+				}
+				catch (IllegalAccessException e) {
+					throw new IOException(e);
+				}
+			}
+			cl = cl.getSuperclass();
+		}
+		jg.writeFieldName("jsonProperties");
+		if (jsonPropFields != null) {
+			jg.writeStartObject();
+			if (jsonPropertiesValue != null) {
+				try {
+					JSONObject jo = new JSONObject(jsonPropertiesValue);
+					Iterator<String> it = jo.keys();
+			         while(it.hasNext()) {
+			             String key = it.next();
+			             jg.writeFieldName(key);
+			             jg.writeObject(jo.get(key));
+					}					
+				}
+				catch (JSONException e) {
+					throw new IOException(e);					
+				}
+			}
+			for (JSONPropField jpf:jsonPropFields) {
+				jg.writeFieldName(jpf.name);
+				jg.writeObject(jpf.value);								
+			}
+			jg.writeEndObject();				
+		}
+		else {
+			jg.writeString(jsonPropertiesValue);
+		}
+		jg.writeEndObject();
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-api/src/main/java/org/apache/atlas/odf/json/DefaultODFDeserializer.java
----------------------------------------------------------------------
diff --git a/odf/odf-api/src/main/java/org/apache/atlas/odf/json/DefaultODFDeserializer.java b/odf/odf-api/src/main/java/org/apache/atlas/odf/json/DefaultODFDeserializer.java
new file mode 100755
index 0000000..d1ae80e
--- /dev/null
+++ b/odf/odf-api/src/main/java/org/apache/atlas/odf/json/DefaultODFDeserializer.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed 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.atlas.odf.json;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+
+public class DefaultODFDeserializer<T> extends StdDeserializer<T> {
+	private static final long serialVersionUID = 4895771352050172936L;
+
+	Logger logger = Logger.getLogger(DefaultODFDeserializer.class.getName());
+
+	Class<? extends T> defaultClass;
+
+	public DefaultODFDeserializer(Class<T> cl, Class<? extends T> defaultClass) {
+		super(cl);
+		this.defaultClass = defaultClass;
+	}
+
+	ClassLoader getClassLoader() {
+		return this.getClass().getClassLoader();
+	}
+
+	@Override
+	public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+		ObjectMapper jpom = ((ObjectMapper) jp.getCodec());
+		JsonNode tree = jpom.readTree(jp);
+		String jsonString = tree.toString();
+
+		Class<? extends T> javaClass = null;
+		String javaClassName = null;
+		try {
+			JsonNode javaClassNode = tree.get("javaClass");
+			javaClassName = javaClassNode.asText();
+			logger.log(Level.FINEST, "Trying to deserialize object of java class {0}", javaClassName);
+			javaClass = (Class<? extends T>) this.getClassLoader().loadClass(javaClassName);
+			if (javaClass != null) {
+				if (!javaClass.equals(this.handledType())) {
+					return jpom.readValue(jsonString, javaClass);
+				}
+			}
+		} catch (Exception exc) {
+			String msg = MessageFormat.format("Java class ''{0}'' could not be deserialized automatically (probably because it is not on the classpath)", javaClassName);
+			logger.warning(msg);
+			logger.log(Level.FINE, msg, exc);
+		}
+		return jpom.readValue(jsonString, defaultClass);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-api/src/main/java/org/apache/atlas/odf/json/JSONUtils.java
----------------------------------------------------------------------
diff --git a/odf/odf-api/src/main/java/org/apache/atlas/odf/json/JSONUtils.java b/odf/odf-api/src/main/java/org/apache/atlas/odf/json/JSONUtils.java
new file mode 100755
index 0000000..fe9d592
--- /dev/null
+++ b/odf/odf-api/src/main/java/org/apache/atlas/odf/json/JSONUtils.java
@@ -0,0 +1,254 @@
+/**
+ * Licensed 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.atlas.odf.json;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.wink.json4j.JSONArray;
+import org.apache.wink.json4j.JSONException;
+import org.apache.wink.json4j.JSONObject;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.Version;
+import com.fasterxml.jackson.databind.Module;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import org.apache.atlas.odf.api.metadata.UnknownMetaDataObject;
+import org.apache.atlas.odf.api.metadata.models.Annotation;
+import org.apache.atlas.odf.api.metadata.models.ClassificationAnnotation;
+import org.apache.atlas.odf.api.metadata.models.Connection;
+import org.apache.atlas.odf.api.metadata.models.ConnectionInfo;
+import org.apache.atlas.odf.api.metadata.models.DataSet;
+import org.apache.atlas.odf.api.metadata.models.DataStore;
+import org.apache.atlas.odf.api.metadata.models.MetaDataObject;
+import org.apache.atlas.odf.api.metadata.models.ProfilingAnnotation;
+import org.apache.atlas.odf.api.metadata.models.RelationshipAnnotation;
+import org.apache.atlas.odf.api.metadata.models.UnknownDataSet;
+import org.apache.atlas.odf.api.metadata.models.UnknownConnection;
+import org.apache.atlas.odf.api.metadata.models.UnknownConnectionInfo;
+import org.apache.atlas.odf.api.metadata.models.UnknownDataStore;
+
+public class JSONUtils {
+	
+	public static HashSet<String> annotationFields = new HashSet<String>();
+	
+	static {
+		for (Class<?> cl: new Class<?>[]{Annotation.class, ProfilingAnnotation.class, ClassificationAnnotation.class,RelationshipAnnotation.class}) {
+			while (cl != Object.class) {   // process class hierarchy up to and including MetaDataObject.class
+				Field fields[] = cl.getDeclaredFields();
+				for (Field f: fields) {
+					f.setAccessible(true);
+					annotationFields.add(f.getName());
+				}
+				cl = cl.getSuperclass();
+			}			
+		}
+	}
+
+
+
+	// reuse object mapper for performance
+	private static ObjectMapper om = null;
+
+	static {
+		om = new ObjectMapper();
+		Module mod = createDefaultObjectMapperModule();
+		om.registerModule(mod);
+	}
+
+	public static ObjectMapper getGlobalObjectMapper() {
+		return om;
+	}
+
+	static Module createDefaultObjectMapperModule() {
+		SimpleModule mod = new SimpleModule("ODF Jackson module", Version.unknownVersion());
+		mod.addDeserializer(Annotation.class, new AnnotationDeserializer());
+		mod.addDeserializer(MetaDataObject.class, new DefaultODFDeserializer<MetaDataObject>(MetaDataObject.class, UnknownMetaDataObject.class));
+		mod.addDeserializer(DataSet.class, new DefaultODFDeserializer<DataSet>(DataSet.class, UnknownDataSet.class));
+		mod.addDeserializer(DataStore.class, new DefaultODFDeserializer<DataStore>(DataStore.class, UnknownDataStore.class));
+		mod.addDeserializer(Connection.class, new DefaultODFDeserializer<Connection>(Connection.class, UnknownConnection.class));
+		mod.addDeserializer(ConnectionInfo.class, new DefaultODFDeserializer<ConnectionInfo>(ConnectionInfo.class, UnknownConnectionInfo.class));
+		
+		mod.addSerializer(Annotation.class, new AnnotationSerializer());
+		return mod;
+
+	}
+	
+	public static JSONObject toJSONObject(Object o) throws JSONException {
+		JSONObject result;
+		try {
+			result = new JSONObject(om.writeValueAsString(o));
+			if (o instanceof Annotation) {
+				Object jsonPropsObject = result.get("jsonProperties");
+				if (jsonPropsObject instanceof JSONObject) {    // the value of jsonProperties must be of type 'String'
+					result.put("jsonProperties", ((JSONObject)jsonPropsObject).toString());	
+				}
+			}
+		} catch (JsonProcessingException e) {
+			throw new JSONException(e);
+		}
+		return result;
+	}
+
+	public static String toJSON(Object o) throws JSONException {
+		String result;
+		try {
+			result = om.writeValueAsString(o);
+			if (o instanceof Annotation) {
+				JSONObject json = new JSONObject(result);
+				Object jsonPropsObject = json.get("jsonProperties");
+				if (jsonPropsObject instanceof JSONObject) {    // the value of jsonProperties must be of type 'String'
+					json.put("jsonProperties", ((JSONObject)jsonPropsObject).toString());	
+					result = json.toString();
+				}
+			}
+		} catch (JsonProcessingException e) {
+			throw new JSONException(e);
+		}
+		return result;
+	}
+
+	public static <T> List<T> fromJSONList(String s, Class<T> cl) throws JSONException {
+		JSONArray ar = new JSONArray(s);
+		List<T> result = new ArrayList<>();
+		for (Object o : ar) {
+			JSONObject jo = (JSONObject) o;
+			T t = (T) fromJSON(jo.write(), cl);
+			result.add(t);
+		}
+		return result;
+
+	}
+
+	public static <T> List<T> fromJSONList(InputStream is, Class<T> cl) throws JSONException {
+		JSONArray ar = new JSONArray(is);
+		List<T> result = new ArrayList<>();
+		for (Object o : ar) {
+			JSONObject jo = (JSONObject) o;
+			T t = (T) fromJSON(jo.write(), cl);
+			result.add(t);
+		}
+		return result;
+	}
+
+	public static <T> T fromJSON(String s, Class<T> cl) throws JSONException {
+		T result = null;
+		try {
+			result = om.readValue(s, cl);
+		} catch (JsonProcessingException exc) {
+			// propagate JSON exception
+			throw new JSONException(exc);
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		}
+
+		return result;
+	}
+
+	public static <T> T fromJSON(InputStream is, Class<T> cl) throws JSONException {
+		return fromJSON(getInputStreamAsString(is, "UTF-8"), cl);
+	}
+
+	public static <T> T readJSONObjectFromFileInClasspath(Class<T> cl, String pathToFile, ClassLoader classLoader) {
+		if (classLoader == null) {
+			// use current classloader if not provided
+			classLoader = JSONUtils.class.getClassLoader();
+		}
+		InputStream is = classLoader.getResourceAsStream(pathToFile);
+		T result = null;
+		try {
+			result = om.readValue(is, cl);
+		} catch (IOException e) {
+			// assume that this is a severe error since the provided JSONs should be correct
+			throw new RuntimeException(e);
+		}
+
+		return result;
+	}
+
+	public static <T> T cloneJSONObject(T obj) throws JSONException {
+		// special case: use Annotation.class in case obj is an annotation subclass to ensure that the annotation deserializer is used
+		if (Annotation.class.isAssignableFrom(obj.getClass())) {
+			return (T) fromJSON(toJSON(obj), Annotation.class);
+		}
+		return fromJSON(toJSON(obj), (Class<T>) obj.getClass());
+	}
+
+	
+	public static void mergeJSONObjects(JSONObject source, JSONObject target) {
+		if (source != null && target != null) {
+			target.putAll(source);
+		}
+	}
+
+	// use this method, e.g., if you want to use JSON objects in log / trace messages
+	// and want to do serialization only if tracing is on
+	public static Object lazyJSONSerializer(final Object jacksonObject) {
+		return new Object() {
+
+			@Override
+			public String toString() {
+				try {
+					return toJSON(jacksonObject);
+				} catch (JSONException e) {
+					return e.getMessage();
+				}
+			}
+
+		};
+	}
+
+	public static Object jsonObject4Log(final JSONObject obj) {
+		return new Object() {
+
+			@Override
+			public String toString() {
+				try {
+					return obj.write();
+				} catch (Exception e) {
+					return e.getMessage();
+				}
+			}
+
+		};
+	}
+
+	public static String getInputStreamAsString(InputStream is, String encoding) {
+		try {
+			final int n = 2048;
+			byte[] b = new byte[0];
+			byte[] temp = new byte[n];
+			int bytesRead;
+			while ((bytesRead = is.read(temp)) != -1) {
+				byte[] newB = new byte[b.length + bytesRead];
+				System.arraycopy(b, 0, newB, 0, b.length);
+				System.arraycopy(temp, 0, newB, b.length, bytesRead);
+				b = newB;
+			}
+			String s = new String(b, encoding);
+			return s;
+		} catch (IOException exc) {
+			throw new RuntimeException(exc);
+		}
+	}
+	
+	public static <T, S> T convert(S source, Class<T> targetClass) throws JSONException {
+		return fromJSON(toJSON(source), targetClass);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-api/src/test/java/org/apache/atlas/odf/test/json/ODFJSONSerializationTest.java
----------------------------------------------------------------------
diff --git a/odf/odf-api/src/test/java/org/apache/atlas/odf/test/json/ODFJSONSerializationTest.java b/odf/odf-api/src/test/java/org/apache/atlas/odf/test/json/ODFJSONSerializationTest.java
new file mode 100755
index 0000000..da8d3af
--- /dev/null
+++ b/odf/odf-api/src/test/java/org/apache/atlas/odf/test/json/ODFJSONSerializationTest.java
@@ -0,0 +1,406 @@
+/**
+ * Licensed 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.atlas.odf.test.json;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.UUID;
+import java.util.logging.Logger;
+
+import org.apache.atlas.odf.api.metadata.InvalidReference;
+import org.apache.atlas.odf.api.metadata.StoredMetaDataObject;
+import org.apache.wink.json4j.JSON;
+import org.apache.wink.json4j.JSONException;
+import org.apache.wink.json4j.JSONObject;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import org.apache.atlas.odf.api.discoveryservice.DiscoveryServiceEndpoint;
+import org.apache.atlas.odf.api.discoveryservice.DiscoveryServiceProperties;
+import org.apache.atlas.odf.api.metadata.MetaDataObjectReference;
+import org.apache.atlas.odf.api.metadata.models.Annotation;
+import org.apache.atlas.odf.api.metadata.models.ClassificationAnnotation;
+import org.apache.atlas.odf.api.metadata.models.JDBCConnection;
+import org.apache.atlas.odf.api.metadata.models.JDBCConnectionInfo;
+import org.apache.atlas.odf.api.metadata.models.MetaDataCache;
+import org.apache.atlas.odf.api.metadata.models.MetaDataObject;
+import org.apache.atlas.odf.api.metadata.models.Column;
+import org.apache.atlas.odf.api.metadata.models.Connection;
+import org.apache.atlas.odf.api.metadata.models.ConnectionInfo;
+import org.apache.atlas.odf.api.metadata.models.DataFile;
+import org.apache.atlas.odf.api.metadata.models.DataSet;
+import org.apache.atlas.odf.api.metadata.models.DataStore;
+import org.apache.atlas.odf.api.metadata.models.Database;
+import org.apache.atlas.odf.api.metadata.models.Table;
+import org.apache.atlas.odf.api.metadata.models.ProfilingAnnotation;
+import org.apache.atlas.odf.api.metadata.models.RelationshipAnnotation;
+import org.apache.atlas.odf.api.metadata.models.UnknownDataSet;
+import org.apache.atlas.odf.json.JSONUtils;
+
+public class ODFJSONSerializationTest {
+
+	Logger logger = Logger.getLogger(ODFJSONSerializationTest.class.getName());
+
+	MetaDataObjectReference createNewRef() {
+		MetaDataObjectReference ref = new MetaDataObjectReference();
+		ref.setId(UUID.randomUUID().toString());
+		ref.setRepositoryId("odftestrepositoryid");
+		return ref;
+	}
+
+	static class NewAnnotation extends ProfilingAnnotation {
+		String newProp;
+
+		public String getNewProp() {
+			return newProp;
+		}
+
+		public void setNewProp(String newProp) {
+			this.newProp = newProp;
+		}
+
+	}
+
+	List<MetaDataObject> createTestObjects() throws JSONException, ParseException {
+		List<MetaDataObject> testObjects = new ArrayList<>();
+
+		Column col = new Column();
+		MetaDataObjectReference colref = createNewRef();
+		col.setReference(colref);
+		col.setName("col1");
+		col.setDescription("column desc");
+		col.setDataType("theDatatype");
+
+		Table t = new Table();
+		MetaDataObjectReference tableRef = createNewRef();
+		t.setReference(tableRef);
+		t.setName("Table");
+		t.setDescription("table desc");
+
+		Database db = new Database();
+		MetaDataObjectReference dbref = createNewRef();
+		db.setReference(dbref);
+		db.setName("DB");
+		db.setDescription("db description");
+
+		JDBCConnection jdbcConn = new JDBCConnection();
+		MetaDataObjectReference jdbcConnRef = createNewRef();
+		jdbcConn.setReference(jdbcConnRef);
+		jdbcConn.setName("jdbc connection");
+		jdbcConn.setUser("theUser");
+		jdbcConn.setPassword("thePassword");
+		jdbcConn.setJdbcConnectionString("jdbc:db2:localhost:50000/SAMPLE");
+		db.setConnections(Collections.singletonList(jdbcConnRef));
+
+		ProfilingAnnotation profAnnot1 = new ProfilingAnnotation();
+		MetaDataObjectReference uaRef = createNewRef();
+		profAnnot1.setReference(uaRef);
+		profAnnot1.setProfiledObject(jdbcConnRef);
+		profAnnot1.setJsonProperties("{\"a\": \"b\"}");
+
+		ProfilingAnnotation profAnnot2 = new ProfilingAnnotation();
+		MetaDataObjectReference mdoRef = createNewRef();
+		profAnnot2.setReference(mdoRef);
+		profAnnot2.setProfiledObject(jdbcConnRef);
+		profAnnot2.setJsonProperties("{\"a\": \"b\"}");
+
+		NewAnnotation newAnnot = new NewAnnotation();
+		MetaDataObjectReference newAnnotRef = createNewRef();
+		newAnnot.setReference(newAnnotRef);
+
+		// a generic DataSet
+		UnknownDataSet ds = new UnknownDataSet();
+		ds.setName("generic data set");
+		ds.setReference(createNewRef());
+
+		MetaDataObject[] mdos = new MetaDataObject[] { db, jdbcConn, t, col, profAnnot1, profAnnot2, newAnnot, ds };
+		testObjects.addAll(Arrays.asList(mdos));
+		return testObjects;
+	}
+
+	@Test
+	public void testSerialization() throws Exception {
+		List<MetaDataObject> testObjects = createTestObjects();
+
+		for (MetaDataObject testObject : testObjects) {
+			Class<?> cl = testObject.getClass();
+			logger.info("Testing serialization / deserialization of object: " + testObject + " of class: " + cl);
+
+			String json = JSONUtils.toJSON(testObject);
+			logger.info("Serialized json: " + json);
+
+			Object objStronglyTypedClass;
+			if (testObject instanceof Annotation) { // special treatment for Annotations -> 2nd arg of fromJSON() needs to be Annotation.class
+				objStronglyTypedClass = JSONUtils.fromJSON(json, Annotation.class);
+				Assert.assertEquals(cl, objStronglyTypedClass.getClass());
+			}
+			else {
+				 objStronglyTypedClass = JSONUtils.fromJSON(json, cl);
+				 Assert.assertEquals(cl, objStronglyTypedClass.getClass());
+			}
+			String json1 = JSONUtils.toJSON(objStronglyTypedClass);
+			Assert.assertEquals(json, json1);
+
+			Object objWithGenericClass = JSONUtils.fromJSON(json, MetaDataObject.class);
+
+			Assert.assertEquals(cl, objWithGenericClass.getClass());
+			String json2 = JSONUtils.toJSON(objWithGenericClass);
+			Assert.assertEquals(json, json2);
+
+			Class<?> intermediateClasses[] = new Class<?>[] { MetaDataObject.class, DataSet.class, DataStore.class, Connection.class };
+
+			for (Class<?> intermediateClass : intermediateClasses) {
+				logger.info("Checking intermediate class: " + intermediateClass);
+				if (intermediateClass.isAssignableFrom(cl)) {
+
+					Object intermediateObject = JSONUtils.fromJSON(json, intermediateClass);
+					logger.info("Deserialized object: " + intermediateObject);
+					logger.info("Deserialized object class: " + intermediateObject.getClass());
+
+					Assert.assertTrue(intermediateClass.isAssignableFrom(intermediateObject.getClass()));
+					Assert.assertEquals(cl, intermediateObject.getClass());
+					String json3 = JSONUtils.toJSON(intermediateObject);
+					Assert.assertEquals(json, json3);
+				}
+			}
+
+		}
+	}
+
+	/**
+	 * Test serialization of an Annotation (subclass) which has both, its own fields (to be mapped to jsonProperties) and
+	 * a non-empty jsonProperties attribute holding the string representation of a Json object.
+	 */
+
+	@Test
+	public void testJsonPropertiesMerge() {
+		NewAnnotation annot = new NewAnnotation();
+		MetaDataObjectReference ref = new MetaDataObjectReference();
+		ref.setId("id");
+		ref.setRepositoryId("repoid");
+		ref.setUrl("http://url");
+		annot.setProfiledObject(ref);
+		annot.setNewProp("newPropValue");
+		annot.setJsonProperties("{\"oldProp\":\"oldPropValue\"}");
+		JSONObject jo = null;
+		try {
+			jo = JSONUtils.toJSONObject(annot);
+			String jsonPropertiesString = jo.getString("jsonProperties");
+			JSONObject jo2 = new JSONObject(jsonPropertiesString);
+			Assert.assertEquals("oldPropValue", jo2.get("oldProp"));
+			Assert.assertEquals("newPropValue", jo2.get("newProp"));
+		}
+		catch (JSONException e) {
+			e.printStackTrace();
+		}
+	}
+
+	final static private String MERGED_JSON = "{" +
+			"\"analysisRun\":null," +
+			"\"summary\":null," +
+			"\"reference\":null," +
+			"\"originRef\":null," +
+			"\"replicaRefs\":null," +
+			"\"javaClass\":\"org.apache.atlas.odf.json.test.ODFJSONSerializationTest$NewAnnotation\"," +
+			"\"jsonProperties\":\"{" +
+			   "\\\"newProp\\\":\\\"newPropValue\\\"," +
+			   "\\\"oldProp\\\":\\\"oldPropValue\\\"" +
+			   "}\"," +
+			"\"name\":null," +
+			"\"annotationType\":\"NewAnnotation\"," +
+			"\"description\":null," +
+			"\"profiledObject\":{" +
+			   "\"repositoryId\":\"repoid\"," +
+			   "\"id\":\"id\"," +
+			   "\"url\":\"http://url\"}" +
+	        "}";
+
+	/**
+	 * Test deserialization of a Json object which has fields in its jsonProperties that can not be mapped to native fields of
+	 * the target class (= value of javaClass field). These and only these remain as fields in the text encoded Json object
+	 * stored in the jsonProperties field of the result.
+	 */
+
+	@Test
+	@Ignore
+	public void testJsonPropertiesUnmerge() throws Exception {
+		logger.info("Deserializing JSON: " + MERGED_JSON);
+		Annotation annot = JSONUtils.fromJSON(MERGED_JSON, Annotation.class);
+		Assert.assertTrue(annot instanceof NewAnnotation);
+		NewAnnotation newAnnot = (NewAnnotation) annot;
+		Assert.assertEquals("newPropValue", newAnnot.getNewProp());
+		JSONObject props = (JSONObject) JSON.parse(annot.getJsonProperties());
+
+		Assert.assertNotNull(props.get("oldProp"));
+		Assert.assertEquals("oldPropValue", props.get("oldProp"));
+
+		JSONObject jo = JSONUtils.toJSONObject(annot);
+		Assert.assertEquals(MERGED_JSON, jo.toString());
+	}
+
+	final private static String PROFILING_ANNOTATION_JSON = "{" +
+			"\"profiledObject\": null," +
+			"\"annotationType\": \"MySubType1\"," +
+			"\"javaClass\": \"org.apache.atlas.odf.core.integrationtest.metadata.atlas.MySubType1\"," +
+			"\"analysisRun\": \"bla\"," +
+			"\"newProp1\": 42," +
+			"\"newProp2\": \"hi\"," +
+			"\"newProp3\": \"hello\"" +
+		"}";
+
+	final private static String CLASSIFICATION_ANNOTATION_JSON = "{" +
+			"\"classifyingObject\": null," +
+			"\"classifiedObject\": null," +
+			"\"annotationType\": \"MySubType2\"," +
+			"\"javaClass\": \"org.apache.atlas.odf.core.integrationtest.metadata.atlas.MySubType2\"," +
+			"\"analysisRun\": \"bla\"," +
+			"\"newProp1\": 42," +
+			"\"newProp2\": \"hi\"," +
+			"\"newProp3\": \"hello\"" +
+		"}";
+
+	final private static String RELATIONSHIP_ANNOTATION_JSON = "{" +
+			"\"relatedObjects\": null," +
+			"\"annotationType\": \"MySubType3\"," +
+			"\"javaClass\": \"org.apache.atlas.odf.core.integrationtest.metadata.atlas.MySubType3\"," +
+			"\"analysisRun\": \"bla\"," +
+			"\"newProp1\": 42," +
+			"\"newProp2\": \"hi\"," +
+			"\"newProp3\": \"hello\"" +
+		"}";
+
+	 /**
+	  *  Replacement for AtlasAnnotationTypeDefinitionCreatTest
+	  */
+
+	@Test
+	public void testSimpleAnnotationPrototypeCreation() throws Exception {
+		logger.info("Annotation string: " + PROFILING_ANNOTATION_JSON);
+		Annotation annot = JSONUtils.fromJSON(PROFILING_ANNOTATION_JSON, Annotation.class);
+		logger.info("Annotation: " + PROFILING_ANNOTATION_JSON);
+		Assert.assertTrue(annot instanceof ProfilingAnnotation);
+
+		logger.info("Annotation string: " + CLASSIFICATION_ANNOTATION_JSON);
+		annot = JSONUtils.fromJSON(CLASSIFICATION_ANNOTATION_JSON, Annotation.class);
+		logger.info("Annotation: " + CLASSIFICATION_ANNOTATION_JSON);
+		Assert.assertTrue(annot instanceof ClassificationAnnotation);
+
+		logger.info("Annotation string: " + RELATIONSHIP_ANNOTATION_JSON);
+		annot = JSONUtils.fromJSON(RELATIONSHIP_ANNOTATION_JSON, Annotation.class);
+		logger.info("Annotation: " + RELATIONSHIP_ANNOTATION_JSON);
+		Assert.assertTrue(annot instanceof RelationshipAnnotation);
+	}
+
+	@Test
+	public void testUnretrievedReference() throws Exception {
+		String repoId = "SomeRepoId";
+		Column col = new Column();
+		col.setName("name");
+		col.setReference(InvalidReference.createInvalidReference(repoId));
+
+		String json = JSONUtils.toJSON(col);
+		Column col2 = JSONUtils.fromJSON(json, Column.class);
+		Assert.assertTrue(InvalidReference.isInvalidRef(col2.getReference()));
+
+		Database db = new Database();
+		db.setName("database");
+
+		JSONUtils.toJSON(db);
+
+		db.setConnections(InvalidReference.createInvalidReferenceList(repoId));
+
+		Database db2 = JSONUtils.fromJSON(JSONUtils.toJSON(db), Database.class);
+		Assert.assertTrue(InvalidReference.isInvalidRefList(db2.getConnections()));
+	}
+
+	@Test
+	public void testExtensibleDiscoveryServiceEndpoints() throws Exception {
+		DiscoveryServiceProperties dsprops = new DiscoveryServiceProperties();
+		dsprops.setId("theid");
+		dsprops.setName("thename");
+
+		DiscoveryServiceEndpoint ep = new DiscoveryServiceEndpoint();
+		ep.setRuntimeName("newruntime");
+		ep.set("someKey", "someValue");
+		dsprops.setEndpoint(ep);
+
+		String dspropsJSON = JSONUtils.toJSON(dsprops);
+		logger.info("Discovery service props JSON: " +dspropsJSON);
+
+		DiscoveryServiceProperties deserProps = JSONUtils.fromJSON(dspropsJSON, DiscoveryServiceProperties.class);
+		Assert.assertNotNull(deserProps);
+		Assert.assertEquals("theid", dsprops.getId());
+		Assert.assertEquals("thename", dsprops.getName());
+		Assert.assertNotNull(deserProps.getEndpoint());
+		Assert.assertTrue(deserProps.getEndpoint() instanceof DiscoveryServiceEndpoint);
+		Assert.assertTrue(deserProps.getEndpoint().getClass().equals(DiscoveryServiceEndpoint.class));
+		DiscoveryServiceEndpoint deserEP = (DiscoveryServiceEndpoint) deserProps.getEndpoint();
+		Assert.assertEquals("newruntime", deserEP.getRuntimeName());
+		Assert.assertEquals("someValue", deserEP.get().get("someKey"));
+	}
+
+	@Test
+	public void testMetaDataCache() {
+		MetaDataCache cache = new MetaDataCache();
+
+		MetaDataObjectReference ref = new MetaDataObjectReference();
+		ref.setId("id");
+		ref.setRepositoryId("repositoryId");
+		DataFile dataFile = new DataFile();
+		dataFile.setName("dataFile");
+		dataFile.setEncoding("encoding");
+		dataFile.setReference(ref);
+
+		List<MetaDataObjectReference> refList = new ArrayList<MetaDataObjectReference>();
+		refList.add(ref);
+		StoredMetaDataObject storedObject = new StoredMetaDataObject(dataFile);
+		HashMap<String, List<MetaDataObjectReference>> referenceMap = new HashMap<String, List<MetaDataObjectReference>>();
+		referenceMap.put("id", refList);
+		storedObject.setReferencesMap(referenceMap);
+		List<StoredMetaDataObject> metaDataObjects = new ArrayList<StoredMetaDataObject>();
+		metaDataObjects.add(storedObject);
+		cache.setMetaDataObjects(metaDataObjects);
+
+		Connection con = new JDBCConnection();
+		con.setName("connection");
+		JDBCConnectionInfo conInfo = new JDBCConnectionInfo();
+		conInfo.setConnections(Collections.singletonList(con));
+		conInfo.setAssetReference(ref);
+		conInfo.setTableName("tableName");
+		List<ConnectionInfo> connectionInfoObjects = new ArrayList<ConnectionInfo>();
+		connectionInfoObjects.add(conInfo);
+		cache.setConnectionInfoObjects(connectionInfoObjects);
+
+		try {
+			String serializedCache = JSONUtils.toJSON(cache);
+			logger.info("Serialized metadata cache JSON: " + serializedCache);
+			MetaDataCache deserializedCache = JSONUtils.fromJSON(serializedCache, MetaDataCache.class);
+			Assert.assertEquals("dataFile", deserializedCache.getMetaDataObjects().get(0).getMetaDataObject().getName());
+			Assert.assertEquals("encoding", ((DataFile) deserializedCache.getMetaDataObjects().get(0).getMetaDataObject()).getEncoding());
+			Assert.assertEquals("connection", deserializedCache.getConnectionInfoObjects().get(0).getConnections().get(0).getName());
+			Assert.assertEquals("tableName", ((JDBCConnectionInfo) deserializedCache.getConnectionInfoObjects().get(0)).getTableName());
+			Assert.assertEquals("repositoryId", deserializedCache.getMetaDataObjects().get(0).getReferenceMap().get("id").get(0).getRepositoryId());
+		}
+		catch (JSONException e) {
+			e.printStackTrace();
+		}
+	}
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-archetype-discoveryservice/.gitignore
----------------------------------------------------------------------
diff --git a/odf/odf-archetype-discoveryservice/.gitignore b/odf/odf-archetype-discoveryservice/.gitignore
new file mode 100755
index 0000000..67c976b
--- /dev/null
+++ b/odf/odf-archetype-discoveryservice/.gitignore
@@ -0,0 +1,17 @@
+#
+#  Licensed 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.
+#
+ .settings
+target
+.classpath
+.project

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-archetype-discoveryservice/pom.xml
----------------------------------------------------------------------
diff --git a/odf/odf-archetype-discoveryservice/pom.xml b/odf/odf-archetype-discoveryservice/pom.xml
new file mode 100755
index 0000000..c9c2aed
--- /dev/null
+++ b/odf/odf-archetype-discoveryservice/pom.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+~
+~ Licensed 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.atlas.odf</groupId>
+		<artifactId>odf</artifactId>
+		<version>1.2.0-SNAPSHOT</version>
+	</parent>
+	<artifactId>odf-archetype-discoveryservice</artifactId>
+	<packaging>maven-archetype</packaging>
+
+	<description>The SDP maven archetype for discovery services</description>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	</properties>
+
+	<build>
+		<extensions>
+			<extension>
+				<groupId>org.apache.maven.archetype</groupId>
+				<artifactId>archetype-packaging</artifactId>
+				<version>2.4</version>
+			</extension>
+		</extensions>
+
+		<pluginManagement>
+			<plugins>
+				<plugin>
+					<artifactId>maven-archetype-plugin</artifactId>
+					<version>2.4</version>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+	</build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-archetype-discoveryservice/src/main/resources/META-INF/maven/archetype.xml
----------------------------------------------------------------------
diff --git a/odf/odf-archetype-discoveryservice/src/main/resources/META-INF/maven/archetype.xml b/odf/odf-archetype-discoveryservice/src/main/resources/META-INF/maven/archetype.xml
new file mode 100755
index 0000000..9848e46
--- /dev/null
+++ b/odf/odf-archetype-discoveryservice/src/main/resources/META-INF/maven/archetype.xml
@@ -0,0 +1,27 @@
+<!--
+~
+~ Licensed 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.
+-->
+<archetype>
+  <id>odf-archetype-discoveryservice-jar</id>
+  <sources>
+    <source>src/main/java/MyAnnotation.java</source>
+    <source>src/main/java/MyDiscoveryService.java</source>
+  </sources>
+  <resources>
+    <resource>src/main/resources/META-INF/odf/odf-services.json</resource>
+  </resources>
+  <testSources>
+    <source>src/test/java/MyDiscoveryServiceTest.java</source>
+  </testSources>
+</archetype>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/pom.xml
----------------------------------------------------------------------
diff --git a/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/pom.xml b/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/pom.xml
new file mode 100755
index 0000000..0ada9e8
--- /dev/null
+++ b/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/pom.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+~
+~ Licensed 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>${groupId}</groupId>
+	<artifactId>${artifactId}</artifactId>
+	<version>${version}</version>
+	<packaging>jar</packaging>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	</properties>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.atlas.odf</groupId>
+			<artifactId>odf-api</artifactId>
+			<version>1.2.0-SNAPSHOT</version>
+		</dependency>
+
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.12</version>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/src/main/java/MyAnnotation.java
----------------------------------------------------------------------
diff --git a/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/src/main/java/MyAnnotation.java b/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/src/main/java/MyAnnotation.java
new file mode 100755
index 0000000..8ce0d2f
--- /dev/null
+++ b/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/src/main/java/MyAnnotation.java
@@ -0,0 +1,30 @@
+/**
+ * Licensed 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 ${package};
+
+import org.apache.atlas.odf.api.metadata.models.ProfilingAnnotation;
+
+public class MyAnnotation extends ProfilingAnnotation {
+
+	private String myProperty;
+
+	public String getMyProperty() {
+		return myProperty;
+	}
+
+	public void setMyProperty(String myValue) {
+		this.myProperty = myValue;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/src/main/java/MyDiscoveryService.java
----------------------------------------------------------------------
diff --git a/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/src/main/java/MyDiscoveryService.java b/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/src/main/java/MyDiscoveryService.java
new file mode 100755
index 0000000..a07ccdb
--- /dev/null
+++ b/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/src/main/java/MyDiscoveryService.java
@@ -0,0 +1,46 @@
+/**
+ * Licensed 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 ${package};
+
+import java.util.Collections;
+import java.util.Date;
+
+import org.apache.atlas.odf.api.discoveryservice.DiscoveryServiceRequest;
+import org.apache.atlas.odf.api.discoveryservice.DiscoveryServiceResponse.ResponseCode;
+import org.apache.atlas.odf.api.discoveryservice.SyncDiscoveryServiceBase;
+import org.apache.atlas.odf.api.discoveryservice.sync.DiscoveryServiceSyncResponse;
+
+/**
+ * A simple synchronous discovery service that creates one annotation for the data set it analyzes.
+ *
+ */
+public class MyDiscoveryService extends SyncDiscoveryServiceBase {
+
+	@Override
+	public DiscoveryServiceSyncResponse runAnalysis(DiscoveryServiceRequest request) {
+		// 1. create an annotation that annotates the data set object passed in the request
+		MyAnnotation annotation = new MyAnnotation();
+		annotation.setProfiledObject(request.getDataSetContainer().getDataSet().getReference());
+		// set a new property called "tutorialProperty" to some string
+		annotation.setMyProperty("My property was created on " + new Date());
+
+		// 2. create a response with our annotation created above
+		return createSyncResponse( //
+				ResponseCode.OK, // Everything works OK
+				"Everything worked", // human-readable message
+				Collections.singletonList(annotation) // new annotations
+		);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/src/main/resources/META-INF/odf/odf-services.json
----------------------------------------------------------------------
diff --git a/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/src/main/resources/META-INF/odf/odf-services.json b/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/src/main/resources/META-INF/odf/odf-services.json
new file mode 100755
index 0000000..e90ce7b
--- /dev/null
+++ b/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/src/main/resources/META-INF/odf/odf-services.json
@@ -0,0 +1,11 @@
+[
+  {
+	"id": "${groupId}.${artifactId}.MyDiscoveryService",
+	"name": "My service",
+	"description": "My service creates my annotation for a data set",
+	"endpoint": {
+		"runtimeName": "Java",
+		"className": "${package}.MyDiscoveryService"
+	}
+  }
+]

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/src/test/java/MyDiscoveryServiceTest.java
----------------------------------------------------------------------
diff --git a/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/src/test/java/MyDiscoveryServiceTest.java b/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/src/test/java/MyDiscoveryServiceTest.java
new file mode 100755
index 0000000..bc585d2
--- /dev/null
+++ b/odf/odf-archetype-discoveryservice/src/main/resources/archetype-resources/src/test/java/MyDiscoveryServiceTest.java
@@ -0,0 +1,28 @@
+/**
+ * Licensed 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 ${package};
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Unit test template for discovery service
+ */
+public class MyDiscoveryServiceTest {
+
+	@Test
+	public void test() throws Exception {
+		Assert.assertTrue(true);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-archetype-discoveryservice/src/test/resources/projects/it1/archetype.properties
----------------------------------------------------------------------
diff --git a/odf/odf-archetype-discoveryservice/src/test/resources/projects/it1/archetype.properties b/odf/odf-archetype-discoveryservice/src/test/resources/projects/it1/archetype.properties
new file mode 100755
index 0000000..9fbb593
--- /dev/null
+++ b/odf/odf-archetype-discoveryservice/src/test/resources/projects/it1/archetype.properties
@@ -0,0 +1,23 @@
+#
+# Licensed 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.
+#
+
+archetype.groupId=org.apache.atlas.odf
+archetype.artifactId=odf-archetype-discoveryservice-jar
+archetype.version=1.2.0-SNAPSHOT
+
+groupId=jg1
+artifactId=ja1
+version=0.1
+package=odf.j.p1.p2
+

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-archetype-discoveryservice/src/test/resources/projects/it1/goal.txt
----------------------------------------------------------------------
diff --git a/odf/odf-archetype-discoveryservice/src/test/resources/projects/it1/goal.txt b/odf/odf-archetype-discoveryservice/src/test/resources/projects/it1/goal.txt
new file mode 100755
index 0000000..3cb5141
--- /dev/null
+++ b/odf/odf-archetype-discoveryservice/src/test/resources/projects/it1/goal.txt
@@ -0,0 +1,14 @@
+#
+#  Licensed 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.
+#
+clean verify

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-atlas/.gitignore
----------------------------------------------------------------------
diff --git a/odf/odf-atlas/.gitignore b/odf/odf-atlas/.gitignore
new file mode 100755
index 0000000..174a0a7
--- /dev/null
+++ b/odf/odf-atlas/.gitignore
@@ -0,0 +1,20 @@
+#
+#  Licensed 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.
+#
+.settings
+target
+.classpath
+.project
+.factorypath
+.DS_Store
+derby.log

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-atlas/atlasconfig/jetty-web.xml
----------------------------------------------------------------------
diff --git a/odf/odf-atlas/atlasconfig/jetty-web.xml b/odf/odf-atlas/atlasconfig/jetty-web.xml
new file mode 100755
index 0000000..66ec730
--- /dev/null
+++ b/odf/odf-atlas/atlasconfig/jetty-web.xml
@@ -0,0 +1,24 @@
+<!--
+~
+~ Licensed 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.
+-->
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+	<Get name="securityHandler">
+		<Set name="loginService">
+			<New class="org.eclipse.jetty.security.HashLoginService">
+				<Set name="name">ODF Realm</Set>
+				<Set name="config"><SystemProperty name="atlas.home" default="."/>/conf/realm.properties</Set>
+			</New>
+		</Set>
+	</Get>
+</Configure>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-atlas/atlasconfig/realm.properties
----------------------------------------------------------------------
diff --git a/odf/odf-atlas/atlasconfig/realm.properties b/odf/odf-atlas/atlasconfig/realm.properties
new file mode 100755
index 0000000..0d57c4a
--- /dev/null
+++ b/odf/odf-atlas/atlasconfig/realm.properties
@@ -0,0 +1,24 @@
+#
+# Licensed 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.
+#
+# Credentials for Atlas basic authentication
+#
+# Format:
+# <username>: <password>[,<rolename> ...]
+#
+# Password is stored in obfuscated format.
+# Re-generate password using the org.eclipse.jetty.util.security.Password class in the jetty lib folder.
+# Example:
+# cd jetty-distribution-<version>/lib
+# java -cp jetty-util-<version>.jar org.eclipse.jetty.util.security.Password <plain password>
+atlas: OBF:1v1p1s3m1w1s1wtw1u3019q71u2a1wui1w1q1s3g1v2p,user

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-atlas/build_atlas.xml
----------------------------------------------------------------------
diff --git a/odf/odf-atlas/build_atlas.xml b/odf/odf-atlas/build_atlas.xml
new file mode 100755
index 0000000..8b6de87
--- /dev/null
+++ b/odf/odf-atlas/build_atlas.xml
@@ -0,0 +1,265 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+~ Licensed 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.
+-->
+<project name="build_atlas">
+	<dirname property="script.basedir" file="${ant.file.build_atlas}" />
+	<property name="atlas-dir" value="apache-atlas-${atlas.version}" />
+	<!-- Properties  provided by pom.xml: -->
+	<!-- <property name="atlas-unpack-dir" value="" /> -->
+	<!-- <property name="atlas.version" value="" /> -->
+
+	<property name="atlas-archive" value="/tmp/${atlas-dir}-bin.zip" />
+
+	<condition property="is-windows">
+		<os family="windows">
+		</os>
+	</condition>
+
+	<condition property="is-unix">
+		<os family="unix">
+		</os>
+	</condition>
+
+	<condition property="is-mac">
+		<os family="mac">
+		</os>
+	</condition>
+
+	<condition property="atlas-zip-not-found">
+		<not>
+			<available file="${atlas-archive}">
+			</available>
+		</not>
+	</condition>
+
+	<condition property="atlas-unpacked">
+	   <available file="${atlas-unpack-dir}/${atlas-dir}/bin/atlas_start.py"/>
+    </condition>
+
+	<condition property="atlas-running">
+		<available file="${atlas-unpack-dir}/${atlas-dir}/logs/atlas.pid"/>
+	</condition>
+
+	<condition property="running-build-process">
+		<equals arg1="${atlas-unpack-dir}" arg2="/tmp"/>
+	</condition>
+
+	<!-- ****************************************************************************************** -->
+
+	<target name="download-atlas" if="atlas-zip-not-found">
+		<echo message="Downloading Apache Atlas 0.7-incubating-release. Depending on your network this can last up to 20 (yes, twenty) minutes." />
+		<!-- Make sure to update text message when moving to a new Atlas release / revision -->
+		<get verbose="true" src="https://ibm.box.com/shared/static/ftwi0wlpjtyv3nnvyh354epayqfwynsn.zip" dest="${atlas-archive}" />
+		<echo message="Atlas downloaded" />
+	</target>
+
+	<target name="unzip-atlas" unless="atlas-unpacked">
+		<antcall target="download-atlas"/>
+		<echo message="Installing Atlas test instance" />
+		<echo message="Deleting ${atlas-unpack-dir}/${atlas-dir}" />
+		<delete dir="${atlas-unpack-dir}/${atlas-dir}" failonerror="false" />
+		<echo message="deleted" />
+		<chmod file="${atlas-unpack-dir}/${atlas-archive}" perm="755" os="unix,mac"/>
+		<unzip src="${atlas-archive}" dest="${atlas-unpack-dir}" />
+	</target>
+
+	<!-- ****************************************************************************************** -->
+
+	<target name="stop-atlas" if="atlas-unpacked">
+		<echo message="Stopping atlas server if it exists" />
+		<exec dir="${atlas-unpack-dir}/${atlas-dir}/bin" executable="python">
+			<env key="JAVA_HOME" value="${java.home}" />
+        		<arg value="atlas_stop.py" />
+    		</exec>
+		<sleep seconds="10" />
+	</target>
+
+	<target name="ensure-atlas-stopped" depends="print-info" unless="use.running.atlas">
+		<echo message="Ensure Atlas is stopped..."/>
+		<antcall target="stop-atlas"/>
+		<delete file="${atlas-unpack-dir}/${atlas-dir}/logs/atlas.pid"/>
+		<echo message="Atlas is stopped."/>
+	</target>
+
+	<target name="remove-atlas-dir" depends="ensure-atlas-stopped" if="running-build-process">
+    	<echo message="Resetting atlas data"/>
+    	<delete dir="/tmp/${atlas-dir}" />
+    	<echo message="Atlas directory deleted"/>
+	</target>
+
+	<target name="reset-derby-data">
+    	<echo message="Resetting derby DB"/>
+    	<delete dir="/tmp/odf-derby" />
+	</target>
+
+	<target name="restart-atlas-on-windows" if="is-windows">
+		<antcall target="start-atlas"/>
+		<antcall target="stop-atlas"/>
+	</target>
+
+	<!-- ****************************************************************************************** -->
+
+	<target name="start-atlas">
+		<echo message="Starting atlas server" />
+		<exec dir="${atlas-unpack-dir}/${atlas-dir}/bin" executable="python">
+			<env key="JAVA_HOME" value="${java.home}/.." />
+			<arg value="atlas_start.py" />
+		</exec>
+		<echo message="Waiting for Atlas Server to start..." />
+		<waitfor maxwait="60" maxwaitunit="second">
+			<socket server="localhost" port="21443" />
+		</waitfor>
+	</target>
+
+	<target name="check-atlas-url">
+		<fail>
+			<condition>
+				<not>
+					<socket server="localhost" port="21443" />
+				</not>
+			</condition>
+		</fail>
+	</target>
+
+	<target name="prepare-atlas" unless="atlas-running">
+		<antcall target="unzip-atlas"/>
+		<antcall target="enable-atlas-ssl"/>
+	</target>
+
+	<!-- ****************************************************************************************** -->
+
+	<target name="import-atlas-sampledata-win" if="is-windows">
+		<echo message="Importing sample data" />
+		<exec executable="cmd">
+			<env key="JAVA_HOME" value="${java.home}" />
+			<arg value="/c" />
+			<arg value="${atlas-unpack-dir}/${atlas-dir}/bin/quick_start.py" />
+		</exec>
+
+		<echo message="Atlas test instance brought up" />
+	</target>
+
+	<target name="import-atlas-sampledata-unix" if="is-unix">
+		<echo message="Importing sample data" />
+		<exec dir="${atlas-unpack-dir}/${atlas-dir}/bin" executable="python">
+			<env key="JAVA_HOME" value="${java.home}" />
+			<arg value="quick_start.py" />
+		</exec>
+
+		<echo message="Atlas test instance brought up" />
+	</target>
+
+	<target name="import-atlas-sampledata" depends="import-atlas-sampledata-win,import-atlas-sampledata-unix">
+	</target>
+
+	<!-- ****************************************************************************************** -->
+
+	<target name="select-atlas-config-file-windows" if="is-windows">
+		<copy file="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties_windows" tofile="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties" overwrite="true"/>
+		<echo message="Using atlas SSL configuration for Windows." />
+	</target>
+
+	<target name="select-atlas-config-file-mac" if="is-mac">
+		<copy file="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties_mac" tofile="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties" overwrite="true"/>
+		<echo message="Using atlas SSL configuration for Mac OS." />
+	</target>
+
+	<target name="select-atlas-config-file-unix" if="is-unix">
+		<copy file="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties_linux" tofile="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties" overwrite="true"/>
+		<echo message="Using atlas SSL configuration for Unix." />
+	</target>
+
+	<target name="select-atlas-config-file" depends="select-atlas-config-file-unix,select-atlas-config-file-windows,select-atlas-config-file-mac">
+	</target>
+
+	<target name="unquote-colons-in-atlas-config-file">
+		<!-- The following replacement is needed because the ant propertyfile task quotes colons and backslashed-->
+		<replace file="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties">
+			<replacetoken>\:</replacetoken>
+			<replacevalue>:</replacevalue>
+		</replace>
+		<replace file="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties">
+			<replacetoken>\\</replacetoken>
+			<replacevalue>\</replacevalue>
+		</replace>
+	</target>
+
+	<target name="enable-atlas-ssl">
+		<!-- For Atlas security features see: http://atlas.incubator.apache.org/Security.html -->
+		<echo message="Updating atlas-application.properties file..." />
+		<propertyfile file="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties">
+			<entry  key="cert.stores.credential.provider.path" value="jceks://file/${sys:atlas.home}/conf/keystore_openjdk.jceks"/>
+			<entry  key="atlas.enableTLS" value="true"/>
+			<entry  key="truststore.file" value="${sys:atlas.home}/conf/keystore_openjdk.jks"/>
+			<entry  key="keystore.file" value="${sys:atlas.home}/conf/keystore_openjdk.jks"/>
+			<entry  key="atlas.server.https.port" value="21443"/>
+			<entry  key="atlas.DeleteHandler.impl" value="org.apache.atlas.repository.graph.HardDeleteHandler"/>
+			<entry  key="atlas.TypeCache.impl" value="org.apache.atlas.repository.typestore.StoreBackedTypeCache"/>
+		</propertyfile>
+		<antcall target="unquote-colons-in-atlas-config-file"/>
+		<!-- Keep this version of the config file for Mac (using oracle/open jdk) -->
+		<copy file="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties" tofile="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties_mac" overwrite="true"/>
+
+		<!-- Create separate version of config file for Linux (using ibm jdk) -->
+		<propertyfile file="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties">
+			<entry  key="cert.stores.credential.provider.path" value="jceks://file/${sys:atlas.home}/conf/keystore_ibmjdk.jceks"/>
+			<entry  key="truststore.file" value="${sys:atlas.home}/conf/keystore_ibmjdk.jks"/>
+			<entry  key="keystore.file" value="${sys:atlas.home}/conf/keystore_ibmjdk.jks"/>
+		</propertyfile>
+		<antcall target="unquote-colons-in-atlas-config-file"/>
+		<copy file="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties" tofile="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties_linux" overwrite="true"/>
+
+		<!-- Create separate version of config file for Windows (using ibm jdk and hardcoded credential provider file (issue #94)) -->
+		<propertyfile file="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties">
+			<entry  key="cert.stores.credential.provider.path" value="jceks://file/C\:/tmp/${atlas-dir}/conf/keystore_ibmjdk.jceks"/>
+		</propertyfile>
+		<antcall target="unquote-colons-in-atlas-config-file"/>
+		<copy file="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties" tofile="${atlas-unpack-dir}/${atlas-dir}/conf/atlas-application.properties_windows" overwrite="true"/>
+
+		<!-- keystore.jceks file is stored in Box@IBM - Re-generate the file using Atlas command bin/cputil.sh -->
+		<!-- Note that ibm jdk uses different format than oracle/open jdk, therefore a separate version has to be generated for each jdk -->
+		<get verbose="true" src="https://ibm.box.com/shared/static/uyzqeayk5ut5f5fqnlvm8nhn9ixb642d.jceks" dest="${atlas-unpack-dir}/${atlas-dir}/conf/keystore_openjdk.jceks" />
+		<get verbose="true" src="https://ibm.box.com/shared/static/ibopoyukw7uhbt83a1zu33nwvnamht3j.jceks" dest="${atlas-unpack-dir}/${atlas-dir}/conf/keystore_ibmjdk.jceks" />
+		<!-- keystore.jks file is stored in Box@IBM - Re-generate the file using the Java keytool -->
+		<!-- command: keytool -genkey -alias myatlas -keyalg RSA -keystore /tmp/atlas-security/keystore.jks -keysize 2048 -->
+		<!-- Note that ibm jdk uses different format than oracle/open jdk, therefore a separate version has to be generated for each jdk -->
+		<get verbose="true" src="https://ibm.box.com/shared/static/odnmhqua5sdue03z43vqsv0lp509ov70.jks" dest="${atlas-unpack-dir}/${atlas-dir}/conf/keystore_openjdk.jks" />
+		<get verbose="true" src="https://ibm.box.com/shared/static/k0qgh31ynbgnjsrbg5s97hsqbssh6pd4.jks" dest="${atlas-unpack-dir}/${atlas-dir}/conf/keystore_ibmjdk.jks" />
+
+		<antcall target="select-atlas-config-file"/>
+		<echo message="Atlas SSL has been enabled." />
+		<!-- On windows, Atlas needs to be re-started again in order for the kafka queues to come up properly -->
+		<antcall target="restart-atlas-on-windows" />
+	</target>
+
+	<!-- ****************************************************************************************** -->
+	<target name="print-info" if="use.running.atlas">
+		<echo message="Don't start/stop Atlas because use.running.atlas is set" />
+	</target>
+
+	<target name="clean-atlas" depends="print-info" unless="use.running.atlas">
+		<echo message="Cleaning Atlas" />
+		<antcall target="remove-atlas-dir"/>
+		<antcall target="reset-derby-data"/>
+	</target>
+
+	<target name="ensure-atlas-running" depends="print-info" unless="use.running.atlas">
+		<echo message="Ensure that Atlas is running" />
+		<antcall target="prepare-atlas" />
+		<antcall target="start-atlas"/>
+		<antcall target="check-atlas-url"/>
+		<echo message="Atlas is running" />
+	</target>
+
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/6d19e129/odf/odf-atlas/pom.xml
----------------------------------------------------------------------
diff --git a/odf/odf-atlas/pom.xml b/odf/odf-atlas/pom.xml
new file mode 100755
index 0000000..cc714e6
--- /dev/null
+++ b/odf/odf-atlas/pom.xml
@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+~
+~ Licensed 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+	xmlns:if="ant:if">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.atlas.odf</groupId>
+		<artifactId>odf</artifactId>
+		<version>1.2.0-SNAPSHOT</version>
+	</parent>
+	<artifactId>odf-atlas</artifactId>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.atlas.odf</groupId>
+			<artifactId>odf-api</artifactId>
+			<version>1.2.0-SNAPSHOT</version>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.atlas.odf</groupId>
+			<artifactId>odf-core</artifactId>
+			<version>1.2.0-SNAPSHOT</version>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.atlas.odf</groupId>
+			<artifactId>odf-messaging</artifactId>
+			<version>1.2.0-SNAPSHOT</version>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.atlas.odf</groupId>
+			<artifactId>odf-messaging</artifactId>
+			<version>1.2.0-SNAPSHOT</version>
+			<type>test-jar</type>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.atlas.odf</groupId>
+			<artifactId>odf-store</artifactId>
+			<version>1.2.0-SNAPSHOT</version>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.atlas.odf</groupId>
+			<artifactId>odf-spark</artifactId>
+			<version>1.2.0-SNAPSHOT</version>
+			<scope>runtime</scope>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.12</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.atlas.odf</groupId>
+			<artifactId>odf-core</artifactId>
+			<version>1.2.0-SNAPSHOT</version>
+			<type>test-jar</type>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.atlas.odf</groupId>
+			<artifactId>odf-spark</artifactId>
+			<version>1.2.0-SNAPSHOT</version>
+			<type>test-jar</type>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.derby</groupId>
+			<artifactId>derby</artifactId>
+			<version>10.12.1.1</version>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-failsafe-plugin</artifactId>
+				<version>2.19</version>
+				<configuration>
+					<systemPropertyVariables>
+						<odf.zookeeper.connect>${testZookeepeConnectionString}</odf.zookeeper.connect>
+						<odf.logspec>${odf.integrationtest.logspec}</odf.logspec>
+						<atlas.url>${atlas.url}</atlas.url>
+						<atlas.user>${atlas.user}</atlas.user>
+						<atlas.password>${atlas.password}</atlas.password>
+					</systemPropertyVariables>
+					<dependenciesToScan>
+						<dependency>org.apache.atlas.odf:odf-core</dependency>
+					</dependenciesToScan>
+					<includes>
+						<include>**/integrationtest/**/**.java</include>
+					</includes>
+				</configuration>
+				<executions>
+					<execution>
+						<id>integration-test</id>
+						<goals>
+							<goal>integration-test</goal>
+						</goals>
+					</execution>
+					<execution>
+						<id>verify</id>
+						<goals>
+							<goal>verify</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+				<version>2.19</version>
+				<configuration>
+					<systemPropertyVariables>
+						<odf.zookeeper.connect>${testZookeepeConnectionString}</odf.zookeeper.connect>
+						<odf.logspec>${odf.unittest.logspec}</odf.logspec>
+						<odf.build.project.name>${project.name}</odf.build.project.name>
+						<atlas.url>${atlas.url}</atlas.url>
+						<atlas.user>${atlas.user}</atlas.user>
+						<atlas.password>${atlas.password}</atlas.password>
+					</systemPropertyVariables>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-antrun-plugin</artifactId>
+				<version>1.8</version>
+				<executions>
+					<execution>
+						<inherited>false</inherited>
+						<id>clean-atlas</id>
+						<phase>clean</phase>
+						<goals>
+							<goal>run</goal>
+						</goals>
+						<configuration>
+							<target>
+								<property name="atlas-unpack-dir" value="/tmp"/>
+								<property name="atlas.version" value="${atlas.version}"/>
+								<ant antfile="build_atlas.xml" target="clean-atlas"/>
+							</target>
+						</configuration>
+					</execution>
+					<execution>
+						<id>ensure-atlas-running</id>
+						<phase>process-test-classes</phase>
+						<!-- <phase>pre-integration-test</phase> -->
+						<goals>
+							<goal>run</goal>
+						</goals>
+						<configuration>
+							<target unless="skipTests">
+								<property name="atlas-unpack-dir" value="/tmp" />
+								<property name="atlas.version" value="${atlas.version}" />
+								<ant antfile="build_atlas.xml" target="ensure-atlas-running"></ant>
+							</target>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+
+	<profiles>
+		<profile>
+			<id>atlas</id>
+			<build>
+				<plugins>
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-antrun-plugin</artifactId>
+						<version>1.8</version>
+						<executions>
+							<!-- Start Atlas even in order to have it available for the test-env when skipping the tests  -->
+							<execution>
+								<id>ensure-atlas-running</id>
+								<phase>process-test-classes</phase>
+								<!-- <phase>pre-integration-test</phase> -->
+								<goals>
+									<goal>run</goal>
+								</goals>
+								<configuration>
+									<target unless="skipTests">
+										<property name="atlas-unpack-dir" value="/tmp" />
+										<property name="atlas.version" value="${atlas.version}" />
+										<ant antfile="build_atlas.xml" target="ensure-atlas-running"></ant>
+									</target>
+								</configuration>
+							</execution>
+						</executions>
+					</plugin>
+				</plugins>
+			</build>
+		</profile>
+	</profiles>
+
+</project>