/**
 * The contents of this file are subject to the OpenMRS Public License
 * Version 1.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://license.openmrs.org
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
 */
package org.openmrs.api.impl;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.api.APIException;
import org.openmrs.api.SerializationService;
import org.openmrs.api.context.Context;
import org.openmrs.serialization.OpenmrsSerializer;
import org.openmrs.serialization.SerializationException;
import org.openmrs.serialization.SimpleXStreamSerializer;
import org.openmrs.util.OpenmrsConstants;
import org.springframework.transaction.annotation.Transactional;

/**
 * Contains methods for retrieving registered OpenmrsSerializer instances, and for
 * persisting/retrieving/deleting objects using serialization
 */
@Transactional
public class SerializationServiceImpl extends BaseOpenmrsService implements SerializationService {
	
	public Log log = LogFactory.getLog(this.getClass());
	
	//***** Properties (set by spring)
	private static Map<Class<? extends OpenmrsSerializer>, OpenmrsSerializer> serializerMap;
	
	//***** Service method implementations *****
	
	/**
	 * @see org.openmrs.api.SerializationService#getSerializer(java.lang.Class)
	 */
	public OpenmrsSerializer getSerializer(Class<? extends OpenmrsSerializer> serializationClass) {
		if (serializerMap != null) {
			return serializerMap.get(serializationClass);
		}
		return null;
	}
	
	/**
	 * @see org.openmrs.api.SerializationService#getDefaultSerializer()
	 */
	public OpenmrsSerializer getDefaultSerializer() {
		String prop = Context.getAdministrationService().getGlobalProperty(
		    OpenmrsConstants.GLOBAL_PROPERTY_DEFAULT_SERIALIZER);
		try {
			Class<?> clazz = Context.loadClass(prop);
			if (clazz != null && OpenmrsSerializer.class.isAssignableFrom(clazz)) {
				return (OpenmrsSerializer) clazz.newInstance();
			}
		}
		catch (Exception e) {
			log.warn("No default serializer specified - trying first serializer found.");
		}
		
		return serializerMap.get(SimpleXStreamSerializer.class);
	}
	
	/**
	 * @see org.openmrs.api.SerializationService#serialize(java.lang.Object, java.lang.Class)
	 */
	public String serialize(Object o, Class<? extends OpenmrsSerializer> clazz) throws SerializationException {
		
		// Get appropriate OpenmrsSerializer implementation
		OpenmrsSerializer serializer = getSerializer(clazz);
		if (serializer == null) {
			throw new SerializationException("OpenmrsSerializer of class <" + clazz + "> not found.");
		}
		
		// Attempt to Serialize the object
		try {
			return serializer.serialize(o);
		}
		catch (Throwable t) {
			throw new SerializationException("An error occurred during serialization of object <" + o + ">", t);
		}
	}
	
	/**
	 * @see org.openmrs.api.SerializationService#deserialize(java.lang.String, java.lang.Class,
	 *      java.lang.Class)
	 */
	public <T extends Object> T deserialize(String serializedObject, Class<? extends T> objectClass,
	        Class<? extends OpenmrsSerializer> serializerClass) throws SerializationException {
		
		// Get appropriate OpenmrsSerializer implementation
		OpenmrsSerializer serializer = getSerializer(serializerClass);
		if (serializer == null) {
			throw new APIException("OpenmrsSerializer of class <" + serializerClass + "> not found.");
		}
		
		// Attempt to Deserialize the object
		try {
			return (T) serializer.deserialize(serializedObject, objectClass);
		}
		catch (Throwable t) {
			String msg = "An error occurred during deserialization of data <" + serializedObject + ">";
			throw new SerializationException(msg, t);
		}
	}
	
	//***** Property access *****
	
	/**
	 * @return the serializers
	 */
	public List<? extends OpenmrsSerializer> getSerializers() {
		if (serializerMap == null) {
			serializerMap = new LinkedHashMap<Class<? extends OpenmrsSerializer>, OpenmrsSerializer>();
		}
		return new ArrayList<OpenmrsSerializer>(serializerMap.values());
	}
	
	/**
	 * @param serializers the serializers to set
	 * @should not reset serializers list when called multiple times
	 */
	public void setSerializers(List<? extends OpenmrsSerializer> serializers) {
		if (serializers == null || serializerMap == null) {
			serializerMap = new LinkedHashMap<Class<? extends OpenmrsSerializer>, OpenmrsSerializer>();
		}
		if (serializers != null) {
			for (OpenmrsSerializer s : serializers) {
				serializerMap.put(s.getClass(), s);
			}
		}
	}
}

@@ -692,24 +692,69 @@
 til.Map;%0D%0A%0D%0A
+import org.apache.commons.lang.StringUtils;%0D%0A
 import org.a
@@ -2315,23 +2315,64 @@
 ER);%0D%0A%09%09
-try %7B%0D%0A
+if (StringUtils.isNotEmpty(prop)) %7B%0D%0A%09%09%09try %7B%0D%0A%09
 %09%09%09Class
@@ -2409,16 +2409,17 @@
 prop);%0D%0A
+%09
 %09%09%09if (c
@@ -2482,24 +2482,25 @@
 (clazz)) %7B%0D%0A
+%09
 %09%09%09%09return (
@@ -2543,24 +2543,27 @@
 ();%0D%0A%09%09%09
+%09
 %7D%0D%0A
+%09
 %09%09%7D%0D%0A
+%09
 %09%09catch 
@@ -2579,16 +2579,17 @@
 n e) %7B%0D%0A
+%09
 %09%09%09log.w
@@ -2660,29 +2660,31 @@
 ound.%22);%0D%0A%09%09
+%09
 %7D%0D%0A%09%09
+%7D
 %0D%0A%09%09return s

Use Default serializer when not defined in global property