diff --git a/build.gradle b/build.gradle
index 8b3159eb7d921506e4ee41cc22366ceab5e892f7..45afa1f18801119db8abb6c77098f7e2004984c2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -126,11 +126,27 @@ cargo {
     }
 }
 
+task sourceJar(type: Jar, dependsOn: classes) {
+    from sourceSets.main.allSource
+}
+
+task javadocJar(type: Jar, dependsOn: javadoc) {
+    from javadoc.destinationDir
+}
+
 publishing {
     publications {
         mavenJava(MavenPublication) {
             from components.java
 
+            artifact sourceJar {
+                classifier "sources"
+            }
+
+            artifact javadocJar {
+                classifier "javadoc"
+            }
+
             pom.withXml {
                 def root = asNode()
                 root.appendNode('name', 'XNAT Server')
diff --git a/src/main/java/org/nrg/dcm/preferences/DicomSCPInstance.java b/src/main/java/org/nrg/dcm/preferences/DicomSCPInstance.java
index 096f3d7f3d433b152e9c384ef70be27668f64f81..0d3a43d1bf1dce89d5f7e47d982375f09c4e53d3 100644
--- a/src/main/java/org/nrg/dcm/preferences/DicomSCPInstance.java
+++ b/src/main/java/org/nrg/dcm/preferences/DicomSCPInstance.java
@@ -1,11 +1,8 @@
 package org.nrg.dcm.preferences;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import java.io.IOException;
 
+@SuppressWarnings("WeakerAccess")
 @JsonInclude(JsonInclude.Include.NON_DEFAULT)
 public class DicomSCPInstance {
     @SuppressWarnings("unused")
@@ -29,14 +26,6 @@ public class DicomSCPInstance {
         setFileNamer(fileNamer);
     }
 
-    public static DicomSCPInstance deserialize(final String json) throws IOException {
-        return _mapper.readValue(json, DicomSCPInstance.class);
-    }
-
-    public static String serialize(final DicomSCPInstance instance) throws IOException {
-        return _mapper.writeValueAsString(instance);
-    }
-
     public String getScpId() {
         return _scpId;
     }
@@ -97,11 +86,6 @@ public class DicomSCPInstance {
                 '}';
     }
 
-    private static final ObjectMapper _mapper = new ObjectMapper();
-    static {
-        _mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
-    }
-
     private String _scpId;
     private int _port;
     private String _aeTitle;
diff --git a/src/main/java/org/nrg/xnat/configuration/SerializerConfig.java b/src/main/java/org/nrg/xnat/configuration/SerializerConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4702c9e57e2c3e2f71ac2d2ffc3ab16919d54f8
--- /dev/null
+++ b/src/main/java/org/nrg/xnat/configuration/SerializerConfig.java
@@ -0,0 +1,47 @@
+package org.nrg.xnat.configuration;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.PrettyPrinter;
+import com.fasterxml.jackson.core.util.DefaultIndenter;
+import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import org.jetbrains.annotations.NotNull;
+import org.nrg.xnat.utils.SerializerService;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SerializerConfig {
+
+    @Bean
+    @NotNull
+    public PrettyPrinter prettyPrinter() {
+        final DefaultIndenter      indenter = new DefaultIndenter("    ", DefaultIndenter.SYS_LF);
+        final DefaultPrettyPrinter printer  = new DefaultPrettyPrinter();
+        printer.indentObjectsWith(indenter);
+        printer.indentArraysWith(indenter);
+        return printer;
+    }
+
+    @Bean
+    public ObjectMapper jsonObjectMapper() {
+        final PrettyPrinter printer = prettyPrinter();
+        final ObjectMapper  mapper  = new ObjectMapper().setDefaultPrettyPrinter(printer);
+        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
+        return mapper;
+    }
+
+    @Bean
+    public ObjectMapper yamlObjectMapper() {
+        final PrettyPrinter printer = prettyPrinter();
+        final ObjectMapper  mapper  = new ObjectMapper(new YAMLFactory()).setDefaultPrettyPrinter(printer);
+        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
+        return mapper;
+    }
+
+    @Bean
+    public SerializerService serializerService() {
+        return new SerializerService();
+    }
+}
diff --git a/src/main/java/org/nrg/xnat/configuration/SpawnerConfig.java b/src/main/java/org/nrg/xnat/configuration/SpawnerConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..93f2d7afcef20a7354af68cf67573b9e31e5d66c
--- /dev/null
+++ b/src/main/java/org/nrg/xnat/configuration/SpawnerConfig.java
@@ -0,0 +1,30 @@
+package org.nrg.xnat.configuration;
+
+import org.nrg.framework.orm.hibernate.HibernateEntityPackageList;
+import org.nrg.xnat.spawner.services.SpawnerResourceLocator;
+import org.nrg.xnat.spawner.services.impl.SpawnerWorker;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Collections;
+
+@Configuration
+@ComponentScan({"org.nrg.xnat.spawner.controllers", "org.nrg.xnat.spawner.services.impl.hibernate", "org.nrg.xnat.spawner.repositories"})
+public class SpawnerConfig {
+    @Bean
+    public SpawnerWorker spawnerWorker() {
+        return new SpawnerWorker();
+    }
+
+    @Bean
+    public HibernateEntityPackageList spawnerEntityPackages() {
+        return new HibernateEntityPackageList(Collections.singletonList("org.nrg.xnat.spawner.entities"));
+    }
+
+    @Bean
+    public SpawnerResourceLocator spawnerResourceLocator() {
+        // TODO: This uses the default spawner element pattern. It would be nice to set this as a site configuration property.
+        return new SpawnerResourceLocator();
+    }
+}
diff --git a/src/main/java/org/nrg/xnat/event/listeners/PipelineEmailHandlerAbst.java b/src/main/java/org/nrg/xnat/event/listeners/PipelineEmailHandlerAbst.java
index b9fc9febc1639b56d477bd5726fe434a89b53d03..f62842042a01eb3421d14f38cac51f6da980fc1f 100644
--- a/src/main/java/org/nrg/xnat/event/listeners/PipelineEmailHandlerAbst.java
+++ b/src/main/java/org/nrg/xnat/event/listeners/PipelineEmailHandlerAbst.java
@@ -1,15 +1,14 @@
 package org.nrg.xnat.event.listeners;
 
 import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.commons.lang.StringUtils;
-import org.apache.log4j.Logger;
 import org.apache.xmlbeans.XmlException;
 import org.nrg.pipeline.xmlbeans.AllResolvedStepsDocument;
 import org.nrg.pipeline.xmlbeans.ParameterData;
+import org.nrg.xdat.XDAT;
 import org.nrg.xdat.model.WrkXnatexecutionenvironmentParameterI;
 import org.nrg.xdat.om.WrkWorkflowdata;
 import org.nrg.xdat.om.WrkXnatexecutionenvironment;
@@ -20,6 +19,9 @@ import org.nrg.xdat.turbine.utils.TurbineUtils;
 import org.nrg.xft.db.PoolDBUtils;
 import org.nrg.xft.event.WorkflowStatusEvent;
 import org.nrg.xnat.notifications.NotifyProjectPipelineListeners;
+import org.nrg.xnat.utils.SerializerService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.io.IOException;
@@ -27,26 +29,25 @@ import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.util.*;
 
-/**
- * Created by flavin on 2/27/15.
- */
+@SuppressWarnings("WeakerAccess")
 public abstract class PipelineEmailHandlerAbst extends WorkflowStatusEventHandlerAbst {
     
-    /** The logger. */
-    static Logger logger = Logger.getLogger(PipelineEmailHandlerAbst.class);
-
     /** The default template success. */
     public final String DEFAULT_TEMPLATE_SUCCESS = "/screens/PipelineEmail_success.vm";
-    
+
     /** The default subject success. */
     public final String DEFAULT_SUBJECT_SUCCESS = "processed without errors";
-    
+
     /** The default template failure. */
     public final String DEFAULT_TEMPLATE_FAILURE = "/screens/PipelineEmail_failure.vm";
-    
+
     /** The default subject failure. */
     public final String DEFAULT_SUBJECT_FAILURE = "";
 
+    protected PipelineEmailHandlerAbst() {
+        _serializer = XDAT.getContextService().getBean(SerializerService.class);
+    }
+
     /**
      * Send.
      *
@@ -93,14 +94,14 @@ public abstract class PipelineEmailHandlerAbst extends WorkflowStatusEventHandle
                 }
 
                 if (completed(e) && Float.parseFloat(wrk.getPercentagecomplete()) < 100.0f) {
-                    logger.error("Workflow "+wrk.getWrkWorkflowdataId()+" is \"Complete\" but percentage is less than 100%. Not sending email.");
+                    _log.error("Workflow " + wrk.getWrkWorkflowdataId() + " is \"Complete\" but percentage is less than 100%. Not sending email.");
                     return;
                 }
                 SchemaElement objXsiType;
                 try {
                     objXsiType = SchemaElement.GetElement(wrk.getDataType());
                 } catch (Throwable e1) {
-                    logger.error("", e1);//this shouldn't happen
+                    _log.error("", e1);//this shouldn't happen
                     return;
                 }
 
@@ -131,24 +132,15 @@ public abstract class PipelineEmailHandlerAbst extends WorkflowStatusEventHandle
                     throw new Exception("Experiment " + wrk.getId() + " associated with workflow " + wrk.getWrkWorkflowdataId() + " is null");
                 }
 
-
-
                 if (wrk.getComments()!=null) {
                     String comments = StringEscapeUtils.unescapeXml(wrk.getComments());
 
                     if (StringUtils.isNotBlank(comments)) {
-                        ObjectMapper objectMapper = new ObjectMapper();
-                        HashMap<String, String> commentsMap = null;
                         try {
-                            commentsMap = objectMapper.readValue(comments, new TypeReference<HashMap<String, String>>(){});
+                            params.putAll(getSerializer().deserializeJson(comments, new TypeReference<HashMap<String, String>>(){}));
                         } catch (Exception e1) {
                             // Do nothing. This isn't necessarily a problem.
-                        }
-
-                        if (commentsMap == null) {
                             params.put("comments",comments);
-                        } else {
-                            params.putAll(commentsMap);
                         }
                     }
                 }
@@ -156,7 +148,6 @@ public abstract class PipelineEmailHandlerAbst extends WorkflowStatusEventHandle
                 if(failed(e)) {
                     // Get a list of parameters. Using that information, find the pipeline execution logs.
                     WrkXnatexecutionenvironment wrkEE=null;
-                    List<WrkXnatexecutionenvironmentParameterI> pipelineCmdLineParameters = null;
                     HashMap<String,String> pipelineCmdLineParamsMap = Maps.newHashMap();
                     HashMap<String,String> pipelineParamsMap = Maps.newHashMap();
                     Map<String,File> attachments = Maps.newHashMap();
@@ -165,9 +156,9 @@ public abstract class PipelineEmailHandlerAbst extends WorkflowStatusEventHandle
                     try {
                         wrkEE = (WrkXnatexecutionenvironment) wrk.getExecutionenvironment();
                     } catch (ClassCastException e1){
-                        logger.error("Workflow Execution Environment is not an XNAT Execution Environment",e1);
+                        _log.error("Workflow Execution Environment is not an XNAT Execution Environment", e1);
                     }
-                    pipelineCmdLineParameters = null==wrkEE ? new ArrayList<WrkXnatexecutionenvironmentParameterI>() : wrkEE.getParameters_parameter();
+                    final List<WrkXnatexecutionenvironmentParameterI> pipelineCmdLineParameters = null == wrkEE ? new ArrayList<WrkXnatexecutionenvironmentParameterI>() : wrkEE.getParameters_parameter();
 
                     // Gather input params from command line
                     for (WrkXnatexecutionenvironmentParameterI pipelineParameter : pipelineCmdLineParameters) {
@@ -193,14 +184,14 @@ public abstract class PipelineEmailHandlerAbst extends WorkflowStatusEventHandle
                                                 stderr = logFileContents;
                                             }
                                         } catch (IOException e1) {
-                                            logger.error("Could not read pipeline log file "+logFileObj.toPath(), e1);
+                                            _log.error("Could not read pipeline log file " + logFileObj.toPath(), e1);
                                         }
                                     } else if (logFileObj.getName().endsWith(".xml")) {
                                         AllResolvedStepsDocument pipeParamsDoc = null;
                                         try {
                                             pipeParamsDoc = AllResolvedStepsDocument.Factory.parse(logFileObj);
                                         } catch (XmlException | IOException e1) {
-                                            logger.error("Encountered a problem parsing pipeline parameter XML for failure email.",e1);
+                                            _log.error("Encountered a problem parsing pipeline parameter XML for failure email.", e1);
                                         }
 
                                         if (null!=pipeParamsDoc) {
@@ -262,7 +253,7 @@ public abstract class PipelineEmailHandlerAbst extends WorkflowStatusEventHandle
 
             }
         } catch (Throwable e1) {
-            logger.error("",e1);
+            _log.error("", e1);
         }
     }
 
@@ -283,5 +274,13 @@ public abstract class PipelineEmailHandlerAbst extends WorkflowStatusEventHandle
         }
         return retList;
     }
+
+    protected SerializerService getSerializer() {
+        return _serializer;
+    }
+
+    private final static Logger _log = LoggerFactory.getLogger(PipelineEmailHandlerAbst.class);
+
+    private final SerializerService _serializer;
 }
 
diff --git a/src/main/java/org/nrg/xnat/helpers/prearchive/PrearcDatabase.java b/src/main/java/org/nrg/xnat/helpers/prearchive/PrearcDatabase.java
index 0cbc305b2f96a0c5230b934c7966c1695ccc0559..29c48d481823db1c27a021daddde0bab95e19cc0 100644
--- a/src/main/java/org/nrg/xnat/helpers/prearchive/PrearcDatabase.java
+++ b/src/main/java/org/nrg/xnat/helpers/prearchive/PrearcDatabase.java
@@ -11,7 +11,6 @@
 package org.nrg.xnat.helpers.prearchive;
 
 import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.base.Strings;
 import com.google.common.collect.Maps;
 import org.apache.commons.collections.CollectionUtils;
@@ -42,6 +41,7 @@ import org.nrg.xnat.restlet.XNATApplication;
 import org.nrg.xnat.restlet.actions.PrearcImporterA.PrearcSession;
 import org.nrg.xnat.restlet.services.Archiver;
 import org.nrg.xnat.turbine.utils.ArcSpecManager;
+import org.nrg.xnat.utils.SerializerService;
 import org.nrg.xnat.utils.XnatUserProvider;
 import org.restlet.data.Status;
 import org.slf4j.Logger;
@@ -61,7 +61,6 @@ import java.util.*;
 
 public final class PrearcDatabase {
     private static final Logger logger = LoggerFactory.getLogger(PrearcTableBuilder.class);
-    public static final ObjectMapper MAPPER = new ObjectMapper(new JsonFactory());
     public static Connection conn;
     final static String table = "prearchive";
     final static String tableWithSchema = PoolDBUtils.search_schema_name + "." + PrearcDatabase.table;
@@ -73,6 +72,8 @@ public final class PrearcDatabase {
 
     private static String prearcPath;
 
+    private static SerializerService _serializer;
+
     public static final String SPLIT_PETMR_SESSION_ID = "SplitPetMrSessions";
 
     public static final String DEFAULT_SPLIT_PETMR_SESSION_FILTER = "{\n" +
@@ -713,10 +714,17 @@ public final class PrearcDatabase {
         } else {
             content = script.getContent();
         }
-        final LinkedHashMap<String, String> keys = MAPPER.readValue(content, SeriesImportFilter.MAP_TYPE_REFERENCE);
+        final LinkedHashMap<String, String> keys = getSerializer().deserializeJson(content, SeriesImportFilter.MAP_TYPE_REFERENCE);
         return DicomFilterService.buildSeriesImportFilter(keys);
     }
 
+    private static SerializerService getSerializer() {
+        if (_serializer == null) {
+            _serializer = XDAT.getContextService().getBean(SerializerService.class);
+        }
+        return _serializer;
+    }
+
     static String getUniqueSessionLabel(final String stem, final String target, final String replacement, final String projectId, final UserI user) {
         String label;
         if (stem.contains(target.toUpperCase())) {
diff --git a/src/main/java/org/nrg/xnat/initialization/XnatWebAppInitializer.java b/src/main/java/org/nrg/xnat/initialization/XnatWebAppInitializer.java
index 55ca5b3e349e21300aa2e6c15056b69d28ec8518..3c4f7fcdcff0763c666d222a2bcab18d6d9ebe31 100644
--- a/src/main/java/org/nrg/xnat/initialization/XnatWebAppInitializer.java
+++ b/src/main/java/org/nrg/xnat/initialization/XnatWebAppInitializer.java
@@ -7,6 +7,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.turbine.Turbine;
 import org.nrg.framework.exceptions.NrgServiceRuntimeException;
 import org.nrg.framework.processors.XnatPluginBean;
+import org.nrg.framework.utilities.BasicXnatResourceLocator;
 import org.nrg.xdat.servlet.XDATAjaxServlet;
 import org.nrg.xdat.servlet.XDATServlet;
 import org.nrg.xnat.restlet.servlet.XNATRestletServlet;
@@ -15,7 +16,6 @@ import org.nrg.xnat.security.XnatSessionEventPublisher;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.core.io.Resource;
-import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
 import org.springframework.core.io.support.PropertiesLoaderUtils;
 import org.springframework.web.filter.DelegatingFilterProxy;
 import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
@@ -114,9 +114,7 @@ public class XnatWebAppInitializer extends AbstractAnnotationConfigDispatcherSer
     private List<Class<?>> getPluginConfigs() {
         final List<Class<?>> configs = new ArrayList<>();
         try {
-            final PathMatchingResourcePatternResolver resolver  = new PathMatchingResourcePatternResolver();
-            final Resource[]                          resources = resolver.getResources("classpath*:META-INF/xnat/**/*-plugin.properties");
-            for (final Resource resource : resources) {
+            for (final Resource resource : BasicXnatResourceLocator.getResources("classpath*:META-INF/xnat/**/*-plugin.properties")) {
                 final Properties     properties = PropertiesLoaderUtils.loadProperties(resource);
                 final XnatPluginBean plugin     = new XnatPluginBean(properties);
                 final Class<?>       config     = plugin.getConfigClass();
diff --git a/src/main/java/org/nrg/xnat/restlet/extensions/DicomSCPRestlet.java b/src/main/java/org/nrg/xnat/restlet/extensions/DicomSCPRestlet.java
index 56617d3280cd269620881c0bc8bb3914b4f61906..03949ce06f1ad400bc72421110cb4507e8c6e79f 100644
--- a/src/main/java/org/nrg/xnat/restlet/extensions/DicomSCPRestlet.java
+++ b/src/main/java/org/nrg/xnat/restlet/extensions/DicomSCPRestlet.java
@@ -11,7 +11,6 @@
 
 package org.nrg.xnat.restlet.extensions;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.base.Joiner;
 import org.apache.commons.lang3.StringUtils;
 import org.nrg.dcm.DicomSCPManager;
@@ -42,10 +41,9 @@ public class DicomSCPRestlet extends SecureResource {
     private static final List<String> ALLOWED_ACTIONS = new ArrayList<>(Arrays.asList("status", "start", "stop", "enable", "disable"));
     private static final Logger       _log            = LoggerFactory.getLogger(DicomSCPRestlet.class);
 
-    private static final ObjectMapper _mapper = new ObjectMapper();
-    private final DicomSCPManager _dicomSCPManager;
-    private final String          _scpId;
-    private final String          _action;
+    private final DicomSCPManager   _dicomSCPManager;
+    private final String            _scpId;
+    private final String            _action;
 
     public DicomSCPRestlet(Context context, Request request, Response response) throws ResourceException {
         super(context, request, response);
@@ -86,11 +84,11 @@ public class DicomSCPRestlet extends SecureResource {
 
         try {
             if (Method.DELETE.equals(getRequest().getMethod()) || (StringUtils.isNotBlank(_action) && _action.equalsIgnoreCase("status"))) {
-                return new StringRepresentation(_mapper.writeValueAsString(_dicomSCPManager.areDicomSCPsStarted()));
+                return new StringRepresentation(getSerializer().toJson(_dicomSCPManager.areDicomSCPsStarted()));
             } else if (StringUtils.isBlank(_scpId)) {
-                return new StringRepresentation(_mapper.writeValueAsString(_dicomSCPManager.getDicomSCPInstances()));
+                return new StringRepresentation(getSerializer().toJson(_dicomSCPManager.getDicomSCPInstances()));
             } else {
-                return new StringRepresentation(DicomSCPInstance.serialize(_dicomSCPManager.getDicomSCPInstance(_scpId)));
+                return new StringRepresentation(getSerializer().toJson(_dicomSCPManager.getDicomSCPInstance(_scpId)));
             }
         } catch (IOException e) {
             throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "An error occurred marshaling the DICOM SCP statuses", e);
@@ -110,8 +108,8 @@ public class DicomSCPRestlet extends SecureResource {
             getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "You should only POST to this URL to create a new DICOM SCP instance. The DICOM SCP ID " + _scpId + " is invalid in this context.");
         }
         try {
-            final String serialized = getRequest().getEntity().getText();
-            final DicomSCPInstance instance = DicomSCPInstance.deserialize(serialized);
+            final String           serialized = getRequest().getEntity().getText();
+            final DicomSCPInstance instance   = getSerializer().deserializeJson(serialized, DicomSCPInstance.class);
             _dicomSCPManager.create(instance);
         } catch (IOException e) {
             getResponse().setStatus(Status.SERVER_ERROR_INTERNAL, e, "An error occurred trying to retrieve the body text of the PUT request.");
diff --git a/src/main/java/org/nrg/xnat/restlet/extensions/PipelineDetailsRestlet.java b/src/main/java/org/nrg/xnat/restlet/extensions/PipelineDetailsRestlet.java
index 30118abd40e2820e295d66db9f1bec63167c4098..117eb76a178e0ad5db3717ecae704b808e157dc7 100644
--- a/src/main/java/org/nrg/xnat/restlet/extensions/PipelineDetailsRestlet.java
+++ b/src/main/java/org/nrg/xnat/restlet/extensions/PipelineDetailsRestlet.java
@@ -10,7 +10,6 @@
  */
 package org.nrg.xnat.restlet.extensions;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.commons.lang.StringUtils;
 import org.nrg.pipeline.PipelineRepositoryManager;
 import org.nrg.pipeline.utils.PipelineFileUtils;
@@ -43,15 +42,13 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-
-
 @XnatRestlet({"/projects/{PROJECT_ID}/pipelines/{PIPELINE_NAME}", "/projects/{PROJECT_ID}/pipelines/{PIPELINE_NAME}/details"})
 public class PipelineDetailsRestlet extends SecureResource {
     public static final String PARAM_PROJECT_ID = "PROJECT_ID";
     public static final String PARAM_PIPELINE_NAME = "PIPELINE_NAME";
 
-    private final String _projectId;
-    private final String _pipelineName;
+    private final String            _projectId;
+    private final String            _pipelineName;
 
     private static final Logger _log = LoggerFactory.getLogger(PipelineDetailsRestlet.class);
 
@@ -79,8 +76,7 @@ public class PipelineDetailsRestlet extends SecureResource {
             Map<String,Object> pipelineDetails = getPipelineDetailsMap();
 
             // Make a json object from the pipelineDetails map
-            ObjectMapper mapper = new ObjectMapper();
-            String json = mapper.writeValueAsString(pipelineDetails);
+            String json = getSerializer().toJson(pipelineDetails);
             return new StringRepresentation(json, MediaType.APPLICATION_JSON);
 
         } catch (Exception exception) {
@@ -119,7 +115,7 @@ public class PipelineDetailsRestlet extends SecureResource {
         }
 
         // Build hash map
-        Map<String,Object> pipelineDetails = new HashMap<String,Object>();
+        Map<String,Object> pipelineDetails = new HashMap<>();
 
         // Basic info
         pipelineDetails.put("path",pipelineDescriptorPath);
@@ -155,9 +151,9 @@ public class PipelineDetailsRestlet extends SecureResource {
                 pipelineDetails.put("publications",doc.getPublications().getPublicationArray());
             }
             if (doc.isSetAuthors()) {
-                List<Map<String,String>> authorInfoList = new ArrayList<Map<String,String>>();
+                List<Map<String,String>> authorInfoList = new ArrayList<>();
                 for (Author aAuthor : doc.getAuthors().getAuthorArray()) {
-                    Map<String,String> authorInfo = new HashMap<String,String>();
+                    Map<String,String> authorInfo = new HashMap<>();
                     if (StringUtils.isNotBlank(aAuthor.getFirstname())) {
                         authorInfo.put("firstname", aAuthor.getFirstname());
                     }
@@ -183,9 +179,9 @@ public class PipelineDetailsRestlet extends SecureResource {
         }
 
         // Step ids and descriptions
-        List<Map<String,String>> stepInfoList = new ArrayList<Map<String,String>>();
+        List<Map<String,String>> stepInfoList = new ArrayList<>();
         for (Step aStep : pipelineData.getSteps().getStepArray()) {
-            Map<String,String> stepInfo = new HashMap<String,String>();
+            Map<String,String> stepInfo = new HashMap<>();
             stepInfo.put("id",aStep.getId());
 
             if (StringUtils.isNotBlank(aStep.getDescription())) {
@@ -196,11 +192,11 @@ public class PipelineDetailsRestlet extends SecureResource {
         pipelineDetails.put("steps",stepInfoList);
 
         // Project-level param defaults
-        List<Map<String,Object>> paramInfoList = new ArrayList<Map<String,Object>>();
+        List<Map<String,Object>> paramInfoList = new ArrayList<>();
         for (ArcPipelineparameterdataI aParamI : projectPipelineData.getParameters_parameter()) {
             ArcPipelineparameterdata aParam = (ArcPipelineparameterdata) aParamI;
 
-            Map<String,Object> paramInfo = new HashMap<String,Object>();
+            Map<String,Object> paramInfo = new HashMap<>();
             paramInfo.put("name",aParam.getName());
             if (StringUtils.isNotBlank(aParam.getDescription())) {
                 paramInfo.put("description", aParam.getDescription());
@@ -209,7 +205,7 @@ public class PipelineDetailsRestlet extends SecureResource {
             String csv = aParam.getCsvvalues();
             String schemaLink = aParam.getSchemalink();
             if (StringUtils.isNotBlank(schemaLink) || StringUtils.isNotBlank(csv)) {
-                Map<String,String> paramValues = new HashMap<String,String>();
+                Map<String,String> paramValues = new HashMap<>();
                 if (StringUtils.isNotBlank(schemaLink)) {
                     paramValues.put("schemaLink",schemaLink);
                 } else {
@@ -223,5 +219,4 @@ public class PipelineDetailsRestlet extends SecureResource {
 
         return pipelineDetails;
     }
-
 }
diff --git a/src/main/java/org/nrg/xnat/restlet/extensions/UserSettingsRestlet.java b/src/main/java/org/nrg/xnat/restlet/extensions/UserSettingsRestlet.java
index 84f4b3bf53c99907be68953de22b708aca9716f0..c0e4474383c9b4cebea78fe556b7585afe51669d 100644
--- a/src/main/java/org/nrg/xnat/restlet/extensions/UserSettingsRestlet.java
+++ b/src/main/java/org/nrg/xnat/restlet/extensions/UserSettingsRestlet.java
@@ -12,7 +12,6 @@ package org.nrg.xnat.restlet.extensions;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -49,8 +48,8 @@ import java.util.*;
 
 @XnatRestlet({"/user", "/user/{USER_ID}", "/user/actions/{ACTION}", "/user/actions/{USER_ID}/{ACTION}"})
 public class UserSettingsRestlet extends SecureResource {
-    public static final String PARAM_USER_ID = "USER_ID";
-    public static final String PARAM_ACTION = "ACTION";
+    private static final String PARAM_USER_ID = "USER_ID";
+    private static final String PARAM_ACTION  = "ACTION";
 
     public UserSettingsRestlet(Context context, Request request, Response response) throws ResourceException {
         super(context, request, response);
@@ -114,7 +113,7 @@ public class UserSettingsRestlet extends SecureResource {
         try {
             if (StringUtils.isBlank(_userId)) {
                 Collection<String> logins = Users.getAllLogins();
-                return new StringRepresentation(_isJsonRequested ? _serializer.writeValueAsString(logins) : createLoginListXml(logins));
+                return new StringRepresentation(_isJsonRequested ? getSerializer().toJson(logins) : createLoginListXml(logins));
             }
 
             UserI requestedUser = Users.getUser(_userId);
@@ -343,7 +342,7 @@ public class UserSettingsRestlet extends SecureResource {
 
     private JsonNode getJsonNode() throws IOException {
         if (_node == null) {
-            _node = _serializer.readValue(_payload, JsonNode.class);
+            _node = getSerializer().deserializeJson(_payload);
         }
         return _node;
     }
@@ -411,7 +410,7 @@ public class UserSettingsRestlet extends SecureResource {
         return new StringRepresentation(output.toString());
     }
 
-    enum UserAction {
+    private enum UserAction {
         Reset,
         ResetEmailRequests;
 
@@ -437,7 +436,7 @@ public class UserSettingsRestlet extends SecureResource {
         private static Map<String, UserAction> _actions = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
     }
 
-    enum UserProperty {
+    private enum UserProperty {
         email,
         enabled,
         firstname,
@@ -458,11 +457,6 @@ public class UserSettingsRestlet extends SecureResource {
     }
 
     private static final Log _log = LogFactory.getLog(UserSettingsRestlet.class);
-    private static final ObjectMapper _serializer = new ObjectMapper() {{
-        // Migration: Get the mix-in annotations working for XDATUser.
-        // getSerializationConfig().addMixInAnnotations(UserI.class, IgnoreSetValueMixIn.class);
-        // getSerializationConfig().addMixInAnnotations(GenericWrapperField.class, IgnoreSetValueMixIn.class);
-    }};
     private static final Map<UserProperty, String> XPATH_EXPRESSIONS = new HashMap<UserProperty, String>() {{
         put(UserProperty.userAuths, "//userAuths/userAuth");
         put(UserProperty.authId, "authId");
diff --git a/src/main/java/org/nrg/xnat/restlet/resources/AutomationResource.java b/src/main/java/org/nrg/xnat/restlet/resources/AutomationResource.java
index 77d98174a1fcb1d5b7c52c04c55c8eccfad4c389..c0d62b297e404d0fc4dae92f524856a2d6cb75c1 100644
--- a/src/main/java/org/nrg/xnat/restlet/resources/AutomationResource.java
+++ b/src/main/java/org/nrg/xnat/restlet/resources/AutomationResource.java
@@ -1,7 +1,9 @@
 package org.nrg.xnat.restlet.resources;
 
 import org.apache.commons.lang.StringUtils;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+import org.nrg.action.ServerException;
 import org.nrg.framework.constants.Scope;
 import org.nrg.xdat.om.XnatProjectdata;
 import org.nrg.xft.XFTTable;
@@ -11,19 +13,27 @@ import org.nrg.xft.event.persist.PersistentWorkflowI;
 import org.nrg.xft.event.persist.PersistentWorkflowUtils;
 import org.nrg.xnat.utils.WorkflowUtils;
 import org.restlet.Context;
+import org.restlet.data.MediaType;
 import org.restlet.data.Request;
 import org.restlet.data.Response;
 import org.restlet.data.Status;
+import org.restlet.resource.Representation;
 import org.restlet.resource.ResourceException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
+import java.nio.charset.Charset;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 
+@SuppressWarnings("WeakerAccess")
 public abstract class AutomationResource extends SecureResource {
 
-    public static final String SITE_SCOPE = Scope.encode(Scope.Site, "");
+    static final         String  SITE_SCOPE      = Scope.encode(Scope.Site, "");
+    private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
 
     public AutomationResource(final Context context, final Request request, final Response response) throws ResourceException {
         super(context, request, response);
@@ -152,6 +162,29 @@ public abstract class AutomationResource extends SecureResource {
         return buffer.toString();
     }
 
+    protected Properties decodeProperties(final Representation entity, final MediaType mediaType) throws ServerException {
+        final Properties properties;
+        if (mediaType.equals(MediaType.APPLICATION_WWW_FORM)) {
+            try {
+                final List<NameValuePair> formMap = URLEncodedUtils.parse(entity.getText(), DEFAULT_CHARSET);
+                properties = new Properties();
+                for (final NameValuePair entry : formMap) {
+                    properties.setProperty(entry.getName(), entry.getValue());
+                }
+            } catch (IOException e) {
+                throw new ServerException(Status.SERVER_ERROR_INTERNAL, "An error occurred trying to read the submitted form body.", e);
+            }
+        } else {
+            try {
+                final String text = entity.getText();
+                properties = getSerializer().deserializeJson(text, Properties.class);
+            } catch (IOException e) {
+                throw new ServerException(Status.SERVER_ERROR_INTERNAL, "An error occurred processing the script properties", e);
+            }
+        }
+        return properties;
+    }
+
     private Map<String, String> validateEntityId(final String entityId) throws ResourceException {
         if (getScope() == null) {
             return null;
@@ -191,8 +224,6 @@ public abstract class AutomationResource extends SecureResource {
         }
     }
 
-    protected static final ObjectMapper MAPPER = new ObjectMapper();
-
     private static final Logger _log = LoggerFactory.getLogger(AutomationResource.class);
     private static final String ENTITY_ID = "ENTITY_ID";
     private static final String PROJECT_ID = "PROJECT_ID";
@@ -201,6 +232,7 @@ public abstract class AutomationResource extends SecureResource {
     private static final String KEY_PROJECTID = "projectId";
     private Scope _scope;
     private boolean _hasProjectId;
+
     private String _projectId;
 
     private final String _path;
diff --git a/src/main/java/org/nrg/xnat/restlet/resources/EventResource.java b/src/main/java/org/nrg/xnat/restlet/resources/EventResource.java
index 14b078f347275d05ac8c8c49e0468882f04e484e..928689f8d727f946d1340afd128dcad2edb07657 100644
--- a/src/main/java/org/nrg/xnat/restlet/resources/EventResource.java
+++ b/src/main/java/org/nrg/xnat/restlet/resources/EventResource.java
@@ -35,8 +35,8 @@ import java.util.Properties;
 
 public class EventResource extends AutomationResource {
 
-    public static final String PROPERTY_EVENT_ID = "event_id";
-    public static final String PROPERTY_EVENT_LABEL = "event_label";
+    private static final String PROPERTY_EVENT_ID    = "event_id";
+    private static final String PROPERTY_EVENT_LABEL = "event_label";
 
     public EventResource(Context context, Request request, Response response) throws ResourceException {
         super(context, request, response);
@@ -142,7 +142,7 @@ public class EventResource extends AutomationResource {
                     final Map<String, String> event = new HashMap<>();
                     event.put(PROPERTY_EVENT_ID, getResourceId());
                     event.put(PROPERTY_EVENT_LABEL, label);
-                    return new StringRepresentation(MAPPER.writeValueAsString(event), mediaType);
+                    return new StringRepresentation(getSerializer().toJson(event), mediaType);
                 }
             } else {
                 // They're asking for list of existing script events, so give them that.
@@ -213,7 +213,7 @@ public class EventResource extends AutomationResource {
                 } else {
                     try {
                         final String text = entity.getText();
-                        _properties.putAll(MAPPER.readValue(text, Properties.class));
+                        _properties.putAll(getSerializer().deserializeJson(text, Properties.class));
                     } catch (IOException e) {
                         throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "An error occurred processing the script properties", e);
                     }
diff --git a/src/main/java/org/nrg/xnat/restlet/resources/ProjectPipelineListResource.java b/src/main/java/org/nrg/xnat/restlet/resources/ProjectPipelineListResource.java
index b81a49a931033297d58a757f4986fa6f6e83b689..d39440c5619a0955326a55f8cc2991b89697e070 100644
--- a/src/main/java/org/nrg/xnat/restlet/resources/ProjectPipelineListResource.java
+++ b/src/main/java/org/nrg/xnat/restlet/resources/ProjectPipelineListResource.java
@@ -87,7 +87,7 @@ public class ProjectPipelineListResource extends SecureResource  {
 					            }
 					        }
 							//Send a 200 OK message back
-							//getResponse().setStatus(Status.SUCCESS_OK,"Pipeline has been removed from project " + proj.getId());
+							//getResponse().setStatus(Status.SUCCESS_OK,"Pipeline has been removed from project " + _project.getId());
 						}
 						}catch(Exception e) {
 							e.printStackTrace();
diff --git a/src/main/java/org/nrg/xnat/restlet/resources/ProjectUserListResource.java b/src/main/java/org/nrg/xnat/restlet/resources/ProjectUserListResource.java
index a36eb43908a51030bfe1a4d21dbfc5f27184aa2f..12a5322df1983e49ea4e95d1d9b5279a0813a7ba 100644
--- a/src/main/java/org/nrg/xnat/restlet/resources/ProjectUserListResource.java
+++ b/src/main/java/org/nrg/xnat/restlet/resources/ProjectUserListResource.java
@@ -17,16 +17,15 @@ import org.nrg.xdat.XDAT;
 import org.nrg.xdat.om.XnatProjectdata;
 import org.nrg.xdat.security.helpers.Permissions;
 import org.nrg.xdat.security.helpers.Roles;
-import org.nrg.xdat.security.helpers.UserHelper;
 import org.nrg.xft.XFTTable;
 import org.nrg.xft.exception.DBPoolException;
-import org.nrg.xft.exception.InvalidItemException;
 import org.restlet.Context;
 import org.restlet.data.MediaType;
 import org.restlet.data.Request;
 import org.restlet.data.Response;
 import org.restlet.data.Status;
 import org.restlet.resource.Representation;
+import org.restlet.resource.ResourceException;
 import org.restlet.resource.Variant;
 
 import java.io.IOException;
@@ -35,51 +34,50 @@ import java.util.Hashtable;
 import java.util.List;
 
 public class ProjectUserListResource extends SecureResource {
-    XFTTable table = null;
-    XnatProjectdata proj = null;
-    boolean displayHiddenUsers = false;
+    private final XnatProjectdata _project;
+    private final boolean         _displayHiddenUsers;
 
     public ProjectUserListResource(Context context, Request request, Response response) throws Exception {
         super(context, request, response);
 
+        setReadable(true);
+        setModifiable(false);
+
         getVariants().add(new Variant(MediaType.APPLICATION_JSON));
         getVariants().add(new Variant(MediaType.TEXT_HTML));
         getVariants().add(new Variant(MediaType.TEXT_XML));
 
         final String projectId = (String) getParameter(request, "PROJECT_ID");
-        if (projectId != null) {
-            proj = XnatProjectdata.getProjectByIDorAlias(projectId, user, false);
-        }
-        if (proj == null) {
+        _project = org.apache.commons.lang3.StringUtils.isNotBlank(projectId) ? XnatProjectdata.getProjectByIDorAlias(projectId, user, false) : null;
+        if (_project == null) {
+            _displayHiddenUsers = false;
             getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND, "The project ID " + projectId + " does not appear to be a valid project ID. Please verify your information.");
         } else {
-                if (!(Roles.isSiteAdmin(user) || Permissions.canEdit(user, proj) || isWhitelisted(projectId))) {
-                    logger.error("Unauthorized Access to project-level user resources. User: " + userName);
-                    getResponse().setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Access Denied: Only project owners and site managers can access user resources.");
-                }
-                displayHiddenUsers = Boolean.parseBoolean((String) getParameter(request, "DISPLAY_HIDDEN_USERS"));
+            if (!(Roles.isSiteAdmin(user) || Permissions.canEdit(user, _project) || isWhitelisted(projectId))) {
+                logger.error("Unauthorized Access to project-level user resources. User: " + userName);
+                getResponse().setStatus(Status.CLIENT_ERROR_FORBIDDEN, "Access Denied: Only project owners and site managers can access user resources.");
             }
+            _displayHiddenUsers = Boolean.parseBoolean((String) getParameter(request, "DISPLAY_HIDDEN_USERS"));
         }
-
-    @Override
-    public boolean allowGet() {
-        return true;
     }
 
     @Override
-    public Representation represent(Variant variant) {
+    public Representation represent(Variant variant) throws ResourceException {
 
-        if (proj != null) {
-            final StringBuilder query = new StringBuilder("SELECT g.id AS \"GROUP_ID\", displayname,login,firstname,lastname,email FROM xdat_userGroup g RIGHT JOIN xdat_user_Groupid map ON g.id=map.groupid RIGHT JOIN xdat_user u ON map.groups_groupid_xdat_user_xdat_user_id=u.xdat_user_id WHERE tag='").append(proj.getId()).append("' ");
+        final XFTTable table;
+        if (_project != null) {
+            final StringBuilder query = new StringBuilder("SELECT g.id AS \"GROUP_ID\", displayname,login,firstname,lastname,email FROM xdat_userGroup g RIGHT JOIN xdat_user_Groupid map ON g.id=map.groupid RIGHT JOIN xdat_user u ON map.groups_groupid_xdat_user_xdat_user_id=u.xdat_user_id WHERE tag='").append(_project.getId()).append("' ");
             try {
-                if(!displayHiddenUsers){
+                if(!_displayHiddenUsers){
                     query.append(" and enabled = 1 ");
                 }
                 query.append(" ORDER BY g.id DESC;");
                 table = XFTTable.Execute(query.toString(), user.getDBName(), user.getLogin());
             } catch (SQLException | DBPoolException e) {
-                logger.warn("An error occurred trying to run the following query: " + query.toString(), e);
+                throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "An error occurred trying to run the following query: " + query.toString(), e);
             }
+        } else {
+            table = null;
         }
 
         Hashtable<String, Object> params = new Hashtable<>();
@@ -92,12 +90,12 @@ public class ProjectUserListResource extends SecureResource {
     }
 
     public boolean isWhitelisted() {
-        final String projectId = (String) proj.getItem().getProps().get("id");
+        final String projectId = (String) _project.getItem().getProps().get("id");
         final ConfigService configService = XDAT.getConfigService();
         final String config = configService.getConfigContents("user-resource-whitelist", "whitelist.json", Scope.Project, projectId);
         if (!StringUtils.isBlank(config)) {
             try {
-                List<String> projectUserResourceWhitelist = OBJECT_MAPPER.readValue(config, TYPE_REFERENCE_LIST_STRING);
+                List<String> projectUserResourceWhitelist = getSerializer().deserializeJson(config, TYPE_REFERENCE_LIST_STRING);
                 if (projectUserResourceWhitelist != null) {
                     return projectUserResourceWhitelist.contains(user.getUsername());
                 }
diff --git a/src/main/java/org/nrg/xnat/restlet/resources/ScriptResource.java b/src/main/java/org/nrg/xnat/restlet/resources/ScriptResource.java
index 6407ba30c303134227511a11a99ca53d64f109ab..92905f33715529813799ac44dc1fa818d0d313e7 100644
--- a/src/main/java/org/nrg/xnat/restlet/resources/ScriptResource.java
+++ b/src/main/java/org/nrg/xnat/restlet/resources/ScriptResource.java
@@ -1,8 +1,6 @@
 package org.nrg.xnat.restlet.resources;
 
 import org.apache.commons.lang.StringUtils;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.utils.URLEncodedUtils;
 import org.nrg.action.ClientException;
 import org.nrg.action.ServerException;
 import org.nrg.automation.entities.Script;
@@ -23,7 +21,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
-import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Hashtable;
 import java.util.List;
@@ -95,7 +92,7 @@ public class ScriptResource extends AutomationResource {
             try {
                 if (StringUtils.isNotBlank(_version)) {
                     //They're requesting a specific version of a specific script
-                    return new StringRepresentation(MAPPER.writeValueAsString(_scriptService.getVersion(_scriptId, _version)), mediaType);
+                    return new StringRepresentation(toJson(_scriptService.getVersion(_scriptId, _version)), mediaType);
                 }
                 else {
                     // They're requesting a specific script, so return that to them.
@@ -110,7 +107,7 @@ public class ScriptResource extends AutomationResource {
 
                     // have to check if it's null, or else it will return a StringRepresentation containing the word null instead of a 404
                     if (script != null) {
-                        return new StringRepresentation(MAPPER.writeValueAsString(script), mediaType);
+                        return new StringRepresentation(toJson(script), mediaType);
                     } else {
                         return null;
                     }
@@ -200,25 +197,7 @@ public class ScriptResource extends AutomationResource {
             throw new ClientException(Status.CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE, "This function currently only supports " + MediaType.APPLICATION_WWW_FORM + " and " + MediaType.APPLICATION_JSON);
         }
 
-        final Properties properties;
-        if (mediaType.equals(MediaType.APPLICATION_WWW_FORM)) {
-            try {
-                final List<NameValuePair> formMap = URLEncodedUtils.parse(entity.getText(), DEFAULT_CHARSET);
-                properties = new Properties();
-                for (final NameValuePair entry : formMap) {
-                    properties.setProperty(entry.getName(), entry.getValue());
-                }
-            } catch (IOException e) {
-                throw new ServerException(Status.SERVER_ERROR_INTERNAL, "An error occurred trying to read the submitted form body.", e);
-            }
-        } else {
-            try {
-                final String text = entity.getText();
-                properties = MAPPER.readValue(text, Properties.class);
-            } catch (IOException e) {
-                throw new ServerException(Status.SERVER_ERROR_INTERNAL, "An error occurred processing the script properties", e);
-            }
-        }
+        final Properties properties = decodeProperties(entity, mediaType);
 
         if (properties.containsKey("scriptId")) {
             properties.remove("scriptId");
@@ -253,7 +232,6 @@ public class ScriptResource extends AutomationResource {
 
     private static final String SCRIPT_ID = "SCRIPT_ID";
     private static final String VERSION = "VERSION";
-    private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
 
     private final ScriptService _scriptService;
     private final ScriptRunnerService _runnerService;
diff --git a/src/main/java/org/nrg/xnat/restlet/resources/ScriptRunnerResource.java b/src/main/java/org/nrg/xnat/restlet/resources/ScriptRunnerResource.java
index 18258397708b816d0b82d8bce965d1b449746d94..31c458d3f9c1ab0c9ccea2fac9adc76cecaf1556 100644
--- a/src/main/java/org/nrg/xnat/restlet/resources/ScriptRunnerResource.java
+++ b/src/main/java/org/nrg/xnat/restlet/resources/ScriptRunnerResource.java
@@ -1,7 +1,5 @@
 package org.nrg.xnat.restlet.resources;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.commons.lang.StringUtils;
 import org.nrg.automation.runners.ScriptRunner;
 import org.nrg.automation.services.ScriptRunnerService;
@@ -58,13 +56,13 @@ public class ScriptRunnerResource extends AutomationResource {
                 if (!_runnerService.hasRunner(_language)) {
                     throw new ResourceException(Status.CLIENT_ERROR_NOT_FOUND, String.format("No script runner found for %s", _language));
                 }
-                final String json = _serializer.writeValueAsString(_runnerService.getRunner(_language));
+                final String json = toJson(_runnerService.getRunner(_language));
                 return new StringRepresentation(json, mediaType);
             } else {
                 final List<String> runners = _runnerService.getRunners();
-                return new StringRepresentation(_serializer.writeValueAsString(runners), mediaType);
+                return new StringRepresentation(toJson(runners), mediaType);
             }
-        } catch (JsonProcessingException e) {
+        } catch (java.io.IOException e) {
             throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "There was an error processing the script runners to JSON", e);
         }
     }
@@ -73,7 +71,6 @@ public class ScriptRunnerResource extends AutomationResource {
 
     private static final String LANGUAGE = "LANGUAGE";
 
-    private static final ObjectMapper _serializer = new ObjectMapper();
     private final ScriptRunnerService _runnerService;
     private final String _language;
 }
diff --git a/src/main/java/org/nrg/xnat/restlet/resources/ScriptTriggerResource.java b/src/main/java/org/nrg/xnat/restlet/resources/ScriptTriggerResource.java
index 1509ea080b85ebd8dc578ab7b2f54911a8e84254..4564240f0462576250900051802ada2ec4df64a4 100644
--- a/src/main/java/org/nrg/xnat/restlet/resources/ScriptTriggerResource.java
+++ b/src/main/java/org/nrg/xnat/restlet/resources/ScriptTriggerResource.java
@@ -1,8 +1,6 @@
 package org.nrg.xnat.restlet.resources;
 
 import org.apache.commons.lang.StringUtils;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.utils.URLEncodedUtils;
 import org.nrg.action.ClientException;
 import org.nrg.action.ServerException;
 import org.nrg.automation.entities.ScriptTrigger;
@@ -22,7 +20,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
-import java.nio.charset.Charset;
 import java.util.*;
 
 public class ScriptTriggerResource extends AutomationResource {
@@ -124,7 +121,7 @@ public class ScriptTriggerResource extends AutomationResource {
         if (_trigger != null) {
             try {
                 // They're requesting a specific trigger, so return that to them.
-                return new StringRepresentation(MAPPER.writeValueAsString(mapTrigger(_trigger)), mediaType);
+                return new StringRepresentation(toJson(mapTrigger(_trigger)), mediaType);
             } catch (IOException e) {
                 throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "An error occurred marshalling the script trigger data to JSON", e);
             }
@@ -245,25 +242,7 @@ public class ScriptTriggerResource extends AutomationResource {
             throw new ClientException(Status.CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE, "This function currently only supports " + MediaType.APPLICATION_WWW_FORM + " and " + MediaType.APPLICATION_JSON);
         }
 
-        final Properties properties;
-        if (mediaType.equals(MediaType.APPLICATION_WWW_FORM)) {
-            try {
-                final List<NameValuePair> formMap = URLEncodedUtils.parse(entity.getText(), DEFAULT_CHARSET);
-                properties = new Properties();
-                for (final NameValuePair entry : formMap) {
-                    properties.setProperty(entry.getName(), entry.getValue());
-                }
-            } catch (IOException e) {
-                throw new ServerException(Status.SERVER_ERROR_INTERNAL, "An error occurred trying to read the submitted form body.", e);
-            }
-        } else {
-            try {
-                final String text = entity.getText();
-                properties = MAPPER.readValue(text, Properties.class);
-            } catch (IOException e) {
-                throw new ServerException(Status.SERVER_ERROR_INTERNAL, "An error occurred processing the script properties", e);
-            }
-        }
+        final Properties properties = decodeProperties(entity, mediaType);
 
         // TODO: These remove definitions of scope, entity ID, and script ID that may be passed in on the API call.
         // TODO: We may consider throwing an exception if something in the body parameters contradicts the URI
@@ -364,7 +343,6 @@ public class ScriptTriggerResource extends AutomationResource {
 
     private static final String EVENT_ID = "EVENT_ID";
     private static final String TRIGGER_ID = "TRIGGER_ID";
-    private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
 
     private final EventService _eventService;
     private final ScriptTriggerService _scriptTriggerService;
diff --git a/src/main/java/org/nrg/xnat/restlet/resources/ScriptTriggerTemplateResource.java b/src/main/java/org/nrg/xnat/restlet/resources/ScriptTriggerTemplateResource.java
index a4318cad192091527e8b94431a87d13b448e604b..4ebd8205034dd6b4f209daeebab30585696fb367 100644
--- a/src/main/java/org/nrg/xnat/restlet/resources/ScriptTriggerTemplateResource.java
+++ b/src/main/java/org/nrg/xnat/restlet/resources/ScriptTriggerTemplateResource.java
@@ -2,7 +2,6 @@ package org.nrg.xnat.restlet.resources;
 
 import com.google.common.base.Joiner;
 import org.apache.commons.lang.StringUtils;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.nrg.action.ClientException;
 import org.nrg.automation.entities.ScriptTrigger;
 import org.nrg.automation.entities.ScriptTriggerTemplate;
@@ -224,7 +223,7 @@ public class ScriptTriggerTemplateResource extends AutomationResource {
         } else if (entity.getMediaType().equals(MediaType.APPLICATION_JSON)) {
             try {
                 final String text = entity.getText();
-                found = MAPPER.readValue(text, ScriptTriggerTemplate.class);
+                found = getSerializer().deserializeJson(text, ScriptTriggerTemplate.class);
             } catch (IOException e) {
                 throw new ClientException(Status.SERVER_ERROR_INTERNAL, "An error occurred processing the script properties", e);
             }
@@ -310,6 +309,4 @@ public class ScriptTriggerTemplateResource extends AutomationResource {
         }
         return persisted.size() > 0 ? persisted : null;
     }
-
-    private static final ObjectMapper MAPPER = new ObjectMapper();
 }
diff --git a/src/main/java/org/nrg/xnat/restlet/resources/ScriptVersionsResource.java b/src/main/java/org/nrg/xnat/restlet/resources/ScriptVersionsResource.java
index 4d62c1824fc4e387817d95eae1e6bce9da1f23b0..b017b3a32cf3b26115a0f0a71550b293427a9080 100644
--- a/src/main/java/org/nrg/xnat/restlet/resources/ScriptVersionsResource.java
+++ b/src/main/java/org/nrg/xnat/restlet/resources/ScriptVersionsResource.java
@@ -21,7 +21,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
-import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Hashtable;
 import java.util.List;
@@ -88,7 +87,7 @@ public class ScriptVersionsResource extends AutomationResource {
 
                 // have to check if it's null, or else it will return a StringRepresentation containing the word null instead of a 404
                 if (versions != null) {
-                    return new StringRepresentation(MAPPER.writeValueAsString(versions), mediaType);
+                    return new StringRepresentation(toJson(versions), mediaType);
                 } else {
                     return null;
                 }
@@ -136,7 +135,6 @@ public class ScriptVersionsResource extends AutomationResource {
     private static final Logger _log = LoggerFactory.getLogger(ScriptVersionsResource.class);
 
     private static final String SCRIPT_ID = "SCRIPT_ID";
-    private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
 
     private final ScriptService _scriptService;
     private final ScriptRunnerService _runnerService;
diff --git a/src/main/java/org/nrg/xnat/restlet/resources/SecureResource.java b/src/main/java/org/nrg/xnat/restlet/resources/SecureResource.java
index 5fc9baa17314e52919d7972b02245a4b34bb0df4..f2d88bc8b39c2d7980a3e2cf40724757ce9aa064 100644
--- a/src/main/java/org/nrg/xnat/restlet/resources/SecureResource.java
+++ b/src/main/java/org/nrg/xnat/restlet/resources/SecureResource.java
@@ -11,7 +11,6 @@
 package org.nrg.xnat.restlet.resources;
 
 import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.collect.Maps;
 import com.noelios.restlet.http.HttpConstants;
 import org.apache.commons.beanutils.BeanUtils;
@@ -67,6 +66,7 @@ import org.nrg.xnat.restlet.representations.*;
 import org.nrg.xnat.restlet.util.FileWriterWrapperI;
 import org.nrg.xnat.restlet.util.RequestUtil;
 import org.nrg.xnat.turbine.utils.ArchivableItem;
+import org.nrg.xnat.utils.SerializerService;
 import org.nrg.xnat.utils.WorkflowUtils;
 import org.restlet.Context;
 import org.restlet.data.*;
@@ -137,9 +137,17 @@ public abstract class SecureResource extends Resource {
 
     protected String csrfToken = null;
 
+    private final SerializerService _serializer;
+
     public SecureResource(Context context, Request request, Response response) {
         super(context, request, response);
 
+        _serializer = XDAT.getContextService().getBean(SerializerService.class);
+        if (null == _serializer) {
+            getResponse().setStatus(Status.CLIENT_ERROR_FAILED_DEPENDENCY, "Serializer service was not properly initialized.");
+            throw new NrgServiceRuntimeException("ERROR: Serializer service was not properly initialized.");
+        }
+
         requested_format = getQueryVariable("format");
 
         // expects that the user exists in the session (either via traditional
@@ -247,6 +255,9 @@ public abstract class SecureResource extends Resource {
         return convertFormToMap(getQueryVariableForm());
     }
 
+    protected SerializerService getSerializer() {
+        return _serializer;
+    }
 
     private Form _body;
     private MediaType _mediaType;
@@ -519,6 +530,10 @@ public abstract class SecureResource extends Resource {
         }
     }
 
+    protected <T> String toJson(final T instance) throws IOException {
+        return getSerializer().toJson(instance);
+    }
+
     public interface ItemHandlerI {
         String getHandlerString();
 
@@ -1522,7 +1537,7 @@ public abstract class SecureResource extends Resource {
         }
 
         try {
-            List<String> userResourceWhitelist = OBJECT_MAPPER.readValue(config, TYPE_REFERENCE_LIST_STRING);
+            List<String> userResourceWhitelist = getSerializer().deserializeJson(config, TYPE_REFERENCE_LIST_STRING);
             if (userResourceWhitelist != null) {
                 return userResourceWhitelist.contains(user.getUsername());
             }
@@ -1534,9 +1549,7 @@ public abstract class SecureResource extends Resource {
         return false;
     }
 
-    protected final static TypeReference<ArrayList<String>> TYPE_REFERENCE_LIST_STRING = new TypeReference<ArrayList<String>>() {
-    };
-    protected final static ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+    protected final static TypeReference<ArrayList<String>> TYPE_REFERENCE_LIST_STRING = new TypeReference<ArrayList<String>>() {};
 
     private static Map<String, List<FilteredResourceHandlerI>> handlers = Maps.newConcurrentMap();
 
diff --git a/src/main/java/org/nrg/xnat/restlet/services/AliasTokenRestlet.java b/src/main/java/org/nrg/xnat/restlet/services/AliasTokenRestlet.java
index 042ce9e13f76650b78b650e4bd65dbbdb4e8d939..fd347ffa82d06f67cfbc5e2ccabc923182bf9d86 100644
--- a/src/main/java/org/nrg/xnat/restlet/services/AliasTokenRestlet.java
+++ b/src/main/java/org/nrg/xnat/restlet/services/AliasTokenRestlet.java
@@ -11,14 +11,13 @@
 package org.nrg.xnat.restlet.services;
 
 import com.google.common.collect.Maps;
-
 import org.apache.commons.lang.StringUtils;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.nrg.xdat.XDAT;
 import org.nrg.xdat.entities.AliasToken;
 import org.nrg.xdat.security.helpers.Roles;
 import org.nrg.xdat.services.AliasTokenService;
 import org.nrg.xnat.restlet.resources.SecureResource;
+import org.nrg.xnat.utils.SerializerService;
 import org.restlet.Context;
 import org.restlet.data.MediaType;
 import org.restlet.data.Request;
@@ -34,15 +33,15 @@ import java.util.HashMap;
 import java.util.Map;
 
 public class AliasTokenRestlet extends SecureResource {
-    public static final String PARAM_OPERATION = "OPERATION";
-    public static final String PARAM_USERNAME = "USERNAME";
-    public static final String PARAM_TOKEN = "TOKEN";
-    public static final String PARAM_SECRET = "SECRET";
-    public static final String OP_ISSUE = "issue";
-    public static final String OP_VALIDATE = "validate";
-    public static final String OP_INVALIDATE = "invalidate";
+    private static final String PARAM_OPERATION = "OPERATION";
+    private static final String PARAM_USERNAME  = "USERNAME";
+    private static final String PARAM_TOKEN     = "TOKEN";
+    private static final String PARAM_SECRET    = "SECRET";
+    private static final String OP_ISSUE        = "issue";
+    private static final String OP_VALIDATE     = "validate";
+    private static final String OP_INVALIDATE   = "invalidate";
 
-    public AliasTokenRestlet(Context context, Request request, Response response) {
+    public AliasTokenRestlet(Context context, Request request, Response response) throws ResourceException {
         super(context, request, response);
         getVariants().add(new Variant(MediaType.APPLICATION_JSON));
         _operation = (String) getRequest().getAttributes().get(PARAM_OPERATION);
@@ -50,6 +49,12 @@ public class AliasTokenRestlet extends SecureResource {
         _token = (String) getRequest().getAttributes().get(PARAM_TOKEN);
         final String secret = (String) getRequest().getAttributes().get(PARAM_SECRET);
         _secret = StringUtils.isBlank(secret) ? INVALID : Long.parseLong(secret);
+
+        _serializer = XDAT.getContextService().getBean(SerializerService.class);
+        if (null == _serializer) {
+            getResponse().setStatus(Status.CLIENT_ERROR_FAILED_DEPENDENCY, "Serializer service was not properly initialized.");
+            throw new ResourceException(Status.CLIENT_ERROR_FAILED_DEPENDENCY, "ERROR: Serializer service was not properly initialized.");
+        }
     }
 
     @Override
@@ -69,9 +74,9 @@ public class AliasTokenRestlet extends SecureResource {
                 throw new ResourceException(Status.CLIENT_ERROR_UNAUTHORIZED, "You must specify both token and secret to validate a token.");
             }
             try {
-                final HashMap<String, String> results = new HashMap<String, String>();
+                final HashMap<String, String> results = new HashMap<>();
                 results.put("valid", getService().validateToken(_token, _secret));
-                return new StringRepresentation(_serializer.writeValueAsString(results));
+                return new StringRepresentation(_serializer.toJson(results));
             } catch (IOException exception) {
                 throw new ResourceException(Status.SERVER_ERROR_INTERNAL, exception.toString());
             }
@@ -89,7 +94,7 @@ public class AliasTokenRestlet extends SecureResource {
         map.put("secret", Long.toString(token.getSecret()));
         String value = "";
         try {
-            value = _serializer.writeValueAsString(map);
+            value = _serializer.toJson(map);
         } catch (IOException e) {
             //
         }
@@ -109,10 +114,10 @@ public class AliasTokenRestlet extends SecureResource {
     }
 
     private static final int INVALID = -1;
-    private static final ObjectMapper _serializer = new ObjectMapper();
-    private AliasTokenService _service;
-    private String _operation;
-    private final String _username;
-    private final String _token;
-    private final long _secret;
+    private final SerializerService _serializer;
+    private       AliasTokenService _service;
+    private       String            _operation;
+    private final String            _username;
+    private final String            _token;
+    private final long              _secret;
 }
diff --git a/src/main/java/org/nrg/xnat/restlet/services/SettingsRestlet.java b/src/main/java/org/nrg/xnat/restlet/services/SettingsRestlet.java
index e1efa228c74e3f15b34358779f3a04025b9b7a7e..5625fdcfef13fe6c9bc871ca79efc491c07652b4 100644
--- a/src/main/java/org/nrg/xnat/restlet/services/SettingsRestlet.java
+++ b/src/main/java/org/nrg/xnat/restlet/services/SettingsRestlet.java
@@ -10,8 +10,6 @@
  */
 package org.nrg.xnat.restlet.services;
 
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.commons.lang.StringUtils;
 import org.hibernate.PropertyNotFoundException;
 import org.nrg.config.entities.Configuration;
@@ -66,12 +64,17 @@ public class SettingsRestlet extends SecureResource {
 
     public SettingsRestlet(Context context, Request request, Response response) throws IOException {
         super(context, request, response);
+
         setModifiable(true);
-        this.getVariants().add(new Variant(MediaType.APPLICATION_JSON));
-        this.getVariants().add(new Variant(MediaType.TEXT_XML));
+
+        getVariants().add(new Variant(MediaType.APPLICATION_JSON));
+        getVariants().add(new Variant(MediaType.TEXT_XML));
+
+        _filterService = XDAT.getContextService().getBean(DicomFilterService.class);
 
         _arcSpec = ArcSpecManager.GetInstance();
         _property = (String) getRequest().getAttributes().get("PROPERTY");
+
         if (!StringUtils.isBlank(_property)) {
             if (_property.equals("initialize")) {
                 if (_arcSpec != null && _arcSpec.isComplete()) {
@@ -103,7 +106,7 @@ public class SettingsRestlet extends SecureResource {
             if (StringUtils.isBlank(_property)) {
                 return mediaType == MediaType.TEXT_XML ?
                         new ItemXMLRepresentation(_arcSpec.getItem(), mediaType) :
-                        new StringRepresentation("{\"ResultSet\":{\"Result\":" + new ObjectMapper().writeValueAsString(getArcSpecAsMap()) + ", \"title\": \"Settings\"}}");
+                        new StringRepresentation("{\"ResultSet\":{\"Result\":" + toJson(getArcSpecAsMap()) + ", \"title\": \"Settings\"}}");
             } else {
                 if (!getArcSpecAsMap().containsKey(_property)) {
                     throw new PropertyNotFoundException(String.format("Setting '%s' was not found in the system.", _property));
@@ -114,7 +117,7 @@ public class SettingsRestlet extends SecureResource {
                     String xml = "<" + _property + ">" + propertyValue.toString() + "</" + _property + ">";
                     return new StringRepresentation(xml, mediaType);
                 } else {
-                    return new StringRepresentation("{\"ResultSet\":{\"Result\":" + new ObjectMapper().writeValueAsString(propertyValue) + ", \"title\": \"" + _property + "\"}}");
+                    return new StringRepresentation("{\"ResultSet\":{\"Result\":" + toJson(propertyValue) + ", \"title\": \"" + _property + "\"}}");
                 }
             }
         } catch (PropertyNotFoundException exception) {
@@ -180,11 +183,6 @@ public class SettingsRestlet extends SecureResource {
     }
 
     private DicomFilterService getDicomFilterService() {
-        if (_filterService == null) {
-            synchronized (_log) {
-                _filterService = XDAT.getContextService().getBean(DicomFilterService.class);
-            }
-        }
         return _filterService;
     }
 
@@ -225,7 +223,7 @@ public class SettingsRestlet extends SecureResource {
                 map.put(atoms[0], atoms[1]);
             }
 
-            return MAPPER.writeValueAsString(map);
+            return toJson(map);
         } catch (IOException ignored) {
             // We're not reading from a file, so we shouldn't encounter this.
         }
@@ -234,7 +232,7 @@ public class SettingsRestlet extends SecureResource {
     }
 
     // TODO: Gross.
-    public static final String ADMIN_USERNAME_FOR_SUBSCRIPTION = "admin";
+    private static final String ADMIN_USERNAME_FOR_SUBSCRIPTION = "admin";
 
     /**
      * This returns the current subscriber or subscribers to a particular <i>site-wide</i> event. If the event doesn't
@@ -934,11 +932,9 @@ public class SettingsRestlet extends SecureResource {
         return users.get(0).getLogin();
     }
 
-    private static final ObjectMapper MAPPER = new ObjectMapper(new JsonFactory());
-
     private static final Logger _log = LoggerFactory.getLogger(SettingsRestlet.class);
 
-    private DicomFilterService _filterService;
+    private final DicomFilterService _filterService;
 
     private NotificationService _notificationService;
     private ArcArchivespecification _arcSpec;
diff --git a/src/main/java/org/nrg/xnat/services/impl/ThemeServiceImpl.java b/src/main/java/org/nrg/xnat/services/impl/ThemeServiceImpl.java
index f72a2cfaab5dae947be92c2b6da130b98c30673c..8f2d1315f6879cf53f9ad0c6562d9c92f3401f8e 100644
--- a/src/main/java/org/nrg/xnat/services/impl/ThemeServiceImpl.java
+++ b/src/main/java/org/nrg/xnat/services/impl/ThemeServiceImpl.java
@@ -12,11 +12,11 @@
 package org.nrg.xnat.services.impl;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.commons.lang.ArrayUtils;
 import org.apache.commons.lang.StringUtils;
 import org.nrg.xnat.configuration.ThemeConfig;
 import org.nrg.xnat.services.ThemeService;
+import org.nrg.xnat.utils.SerializerService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -34,9 +34,11 @@ public class ThemeServiceImpl implements ThemeService {
     private static String themesPath;
     private static ThemeConfig themeConfig = null;
     private static File themeFile = null;
-    protected final ObjectMapper mapper = new ObjectMapper();
     private static final int FILE_BUFFER_SIZE = 4096;
 
+    @Autowired
+    private SerializerService _serializer;
+
     @Autowired
     private ServletContext servletContext;
 
@@ -75,7 +77,7 @@ System.out.println("Theme Path: "+themeFile);
                     }
                     reader.close();
                     String contents = sb.toString();
-                    themeConfig = mapper.readValue(contents, ThemeConfig.class);
+                    themeConfig = _serializer.deserializeJson(contents, ThemeConfig.class);
                 } catch (IOException e) {
                     e.printStackTrace();
                 }
@@ -86,7 +88,7 @@ System.out.println("Theme Path: "+themeFile);
                 e.printStackTrace();
             }
         }
-        if(role != null){
+        if (role != null) {
             // TODO: implement search through the roles array in the ThemeConfig object for a matching ThemeConfig object for the specified role
         }
         return themeConfig;
@@ -130,6 +132,7 @@ System.out.println("Theme Path: "+themeFile);
     private String checkThemeFileExists(ThemeConfig theme, String pageName) {
         return checkThemeFileExists(theme, pageName, null);
     }
+
     private String checkThemeFileExists(ThemeConfig theme, String pageName, String type) {
         String pagePath = null, typeSep = type + "s" + File.separator;
         String[] extensions = new String[]{};
@@ -174,7 +177,7 @@ System.out.println("Theme Path: "+themeFile);
                 themeConfig = new ThemeConfig();
             }
             if(themeExists(themeConfig.getName())) {
-                String themeJson = mapper.writeValueAsString(themeConfig);
+                String themeJson = _serializer.toJson(themeConfig);
                 if (!themeFile.exists()) {
                     themeFile.createNewFile();
                 }
@@ -276,7 +279,7 @@ System.out.println("Theme Path: "+themeFile);
      * @throws IOException
      */
     public List<String> extractTheme(InputStream inputStream) throws IOException {
-        ArrayList rootDirs = new ArrayList();
+        final List<String> rootDirs = new ArrayList<>();
         ZipInputStream zipIn = new ZipInputStream(inputStream);
         ZipEntry entry = zipIn.getNextEntry();
         while (entry != null) {  // iterate over entries in the zip file
@@ -284,8 +287,7 @@ System.out.println("Theme Path: "+themeFile);
             if (!entry.isDirectory()) {  // if the entry is a file, extract it      // TODO: Make sure we get a directory the first iteration through (fail otherwise) so that no files get dumped in the root themes directory
                 this.extractFile(zipIn, filePath);
             } else {  // if the entry is a directory, make the directory
-                String rootDir = "";
-                rootDir = entry.getName();
+                String rootDir = entry.getName();
                 int slashIndex = rootDir.indexOf('/');
                 if(slashIndex>1){
                     int nextSlashIndex = rootDir.indexOf('/', slashIndex+1);
diff --git a/src/main/java/org/nrg/xnat/spawner/controllers/ManageElementsController.java b/src/main/java/org/nrg/xnat/spawner/controllers/ManageElementsController.java
index 2b2ad5a8cd891c4c9c7028fb8eaabaf73c33a6e5..e806046f2010b4aecb9d9785dc8facdeb5896c34 100644
--- a/src/main/java/org/nrg/xnat/spawner/controllers/ManageElementsController.java
+++ b/src/main/java/org/nrg/xnat/spawner/controllers/ManageElementsController.java
@@ -12,20 +12,23 @@ import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.servlet.ModelAndView;
 
 import javax.inject.Inject;
+import java.util.List;
 
+@SuppressWarnings("SpringMVCViewInspection")
 @Controller
 @RequestMapping(value = "/spawner/elements", produces = "application/json")
 public class ManageElementsController {
 
     @RequestMapping
     public ModelAndView getAvailableElements() {
-        return new ModelAndView("spawner/elements", "elements", _service.getAvailableSpawnerElementIds());
+        final List<SpawnerElement> elements = _service.getAll();
+        return new ModelAndView("spawner/elements", "elements", elements);
     }
 
     @RequestMapping(value = "{elementId}", method = RequestMethod.GET)
     public ModelAndView getElement(@PathVariable final String elementId) {
         final SpawnerElement element = _service.retrieve(elementId);
-        return new ModelAndView("spawner/element", element == null ? "error" : "element", element == null ? "The ID element " + elementId + " was not found in the system." : element);
+        return new ModelAndView("spawner/element", element == null ? "error" : "elementId", element == null ? "The ID element " + elementId + " was not found in the system." : elementId);
     }
 
     @RequestMapping(value = "{elementId}", method = RequestMethod.PUT)
diff --git a/src/main/java/org/nrg/xnat/turbine/modules/screens/LaunchUploadApplet.java b/src/main/java/org/nrg/xnat/turbine/modules/screens/LaunchUploadApplet.java
index 2e97b3d45b8a9cf975c0a0430d26c3368aeb11bf..739fb9436059b98b2fd1dea8f28ab38c1d01df2c 100644
--- a/src/main/java/org/nrg/xnat/turbine/modules/screens/LaunchUploadApplet.java
+++ b/src/main/java/org/nrg/xnat/turbine/modules/screens/LaunchUploadApplet.java
@@ -15,7 +15,6 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.turbine.util.RunData;
 import org.apache.velocity.context.Context;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.nrg.framework.utilities.Reflection;
 import org.nrg.xdat.om.XnatPvisitdata;
 import org.nrg.xdat.turbine.utils.TurbineUtils;
@@ -28,24 +27,25 @@ import java.util.List;
  * @author timo
  *
  */
+@SuppressWarnings({"WeakerAccess", "unused"})
 public class LaunchUploadApplet extends UploadAppletScreen {
 	
 	private static final Log _log = LogFactory.getLog(LaunchUploadApplet.class);
-	
 
-	
-	@Override
+    @Override
 	public void doBuildTemplate(RunData data, Context context) {
 		context.put("jsessionid", XnatHttpUtils.getJSESSIONID(data));
 		
-		if(StringUtils.trimToEmpty((String)org.nrg.xdat.turbine.utils.TurbineUtils.GetPassedParameter("search_field",data)).equals("xnat:subjectData.ID")) {
-		    context.put("subject", StringUtils.trimToEmpty((String)org.nrg.xdat.turbine.utils.TurbineUtils.GetPassedParameter("search_value",data)));
+		if(StringUtils.trimToEmpty((String)TurbineUtils.GetPassedParameter("search_field",data)).equals("xnat:subjectData.ID")) {
+		    context.put("subject", StringUtils.trimToEmpty((String)TurbineUtils.GetPassedParameter("search_value",data)));
 		}
 
-        if(StringUtils.isNotBlank((String) org.nrg.xdat.turbine.utils.TurbineUtils.GetPassedParameter("pvisit", data))) {
-            XnatPvisitdata visit = XnatPvisitdata.getXnatPvisitdatasById((String) org.nrg.xdat.turbine.utils.TurbineUtils.GetPassedParameter("pvisit", data), TurbineUtils.getUser(data), false);
-            context.put("subject", visit.getSubjectId());
-            context.put("visit", visit.getId());
+        if(StringUtils.isNotBlank((String) TurbineUtils.GetPassedParameter("pvisit", data))) {
+            final XnatPvisitdata visit = XnatPvisitdata.getXnatPvisitdatasById(TurbineUtils.GetPassedParameter("pvisit", data), TurbineUtils.getUser(data), false);
+            if (visit != null) {
+                context.put("subject", visit.getSubjectId());
+                context.put("visit", visit.getId());
+            }
         }
 
         try {
@@ -62,8 +62,7 @@ public class LaunchUploadApplet extends UploadAppletScreen {
 	        if (json != null) {
 	            try {
 	            	//we have JSON, so, create applet parameters from it.
-	            	ObjectMapper mapper = new ObjectMapper();
-	            	AppletConfig jsonParams = mapper.readValue(json, AppletConfig.class);
+	            	AppletConfig jsonParams = getSerializer().deserializeJson(json, AppletConfig.class);
 
 	            	if(jsonParams.getLaunch() != null){
 	            		for(String key:jsonParams.getLaunch().keySet()){
@@ -79,8 +78,8 @@ public class LaunchUploadApplet extends UploadAppletScreen {
 		}
 	}
 
-    public interface ContextAction {
-        public void execute(RunData data, Context context);
+    private interface ContextAction {
+        void execute(RunData data, Context context);
     }
 
     private void dynamicContextExpansion(RunData data, Context context) throws Exception {
diff --git a/src/main/java/org/nrg/xnat/turbine/modules/screens/UploadApplet.java b/src/main/java/org/nrg/xnat/turbine/modules/screens/UploadApplet.java
index b98bf84bcd5d372a7011f096a1c87b5bb851172a..c78e6e1952416dd77fbc30f17c6b9cecb113a17f 100644
--- a/src/main/java/org/nrg/xnat/turbine/modules/screens/UploadApplet.java
+++ b/src/main/java/org/nrg/xnat/turbine/modules/screens/UploadApplet.java
@@ -12,7 +12,6 @@ package org.nrg.xnat.turbine.modules.screens;
 
 import org.apache.turbine.util.RunData;
 import org.apache.velocity.context.Context;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.nrg.xdat.turbine.utils.TurbineUtils;
 import org.nrg.xnat.turbine.utils.ArcSpecManager;
 import org.nrg.xnat.utils.AppletConfig;
@@ -20,6 +19,7 @@ import org.nrg.xnat.utils.XnatHttpUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+@SuppressWarnings("unused")
 public class UploadApplet extends UploadAppletScreen {
 	private static final Logger logger = LoggerFactory.getLogger(UploadApplet.class);
 	
@@ -41,19 +41,19 @@ public class UploadApplet extends UploadAppletScreen {
         	// HH:MM or if HH:MM == 00:00 the applet will only verify the scan is on the same day as mm/dd/yyyy. If it receives no
         	// session_date, it will prompt the user for one.  With that said, we want to build up the mm/dd/yyyy string if we can.
         	// we'll do it here.
-        	String hhmm = " 00:00";
+        	String time = " 00:00";
         	if (TurbineUtils.HasPassedParameter("session_time_h", data) && TurbineUtils.HasPassedParameter("session_time_m", data)) {
         		// parameters are set with drop-downs so no need to validate here.
         		String hr = (String)TurbineUtils.GetPassedParameter("session_time_h", data);
         		String mm =(String)TurbineUtils.GetPassedParameter("session_time_m", data);
         		try{
         			//poor man's validation
-        			hhmm =  Integer.parseInt(hr) + ":" + Integer.parseInt(mm);
+        			time =  Integer.parseInt(hr) + ":" + Integer.parseInt(mm);
         		} catch (Exception e){
         			//if one or both aren't an integer, we'll get here, which is fine. it just means they didn't select a time. 
         		}
         	}
-            context.put("session_date", ((String)TurbineUtils.GetPassedParameter("session_date", data)).replace('.', '/') + " " + hhmm);
+            context.put("session_date", ((String)TurbineUtils.GetPassedParameter("session_date", data)).replace('.', '/') + " " + time);
         } else if (TurbineUtils.HasPassedParameter("no_session_date", data)) {
             context.put("session_date", "no_session_date");
         }
@@ -67,8 +67,7 @@ public class UploadApplet extends UploadAppletScreen {
 	        if (json != null) {
 	            try {
 	            	//we have JSON, so, create applet parameters from it.
-	            	ObjectMapper mapper = new ObjectMapper();
-	            	AppletConfig jsonParams = mapper.readValue(json, AppletConfig.class);
+	            	AppletConfig jsonParams = getSerializer().deserializeJson(json, AppletConfig.class);
 	            	StringBuilder sb = new StringBuilder();
 	            	if(jsonParams.getParameters() != null) {
 	            		for(String key:jsonParams.getParameters().keySet()) {
diff --git a/src/main/java/org/nrg/xnat/turbine/modules/screens/UploadAppletScreen.java b/src/main/java/org/nrg/xnat/turbine/modules/screens/UploadAppletScreen.java
index b6fdafdd84e09fbcfb55b1bf8919e46b867c46fd..46ad360a7cc91d8c106c383877badbb8ad1f263b 100644
--- a/src/main/java/org/nrg/xnat/turbine/modules/screens/UploadAppletScreen.java
+++ b/src/main/java/org/nrg/xnat/turbine/modules/screens/UploadAppletScreen.java
@@ -8,11 +8,17 @@ import org.nrg.xdat.security.helpers.Permissions;
 import org.nrg.xdat.turbine.modules.screens.SecureScreen;
 import org.nrg.xft.security.UserI;
 import org.nrg.xnat.utils.AppletConfig;
+import org.nrg.xnat.utils.SerializerService;
 
 /**
  * Contains basic methods used by upload applet screen classes.
  */
 public abstract class UploadAppletScreen extends SecureScreen {
+
+    protected UploadAppletScreen() {
+        _serializer = XDAT.getContextService().getBean(SerializerService.class);
+    }
+
     protected org.nrg.config.entities.Configuration getAppletConfiguration(final UserI user, final String projectName) {
         //grab the applet config. Project level if it exists, otherwise, do the site-wide
         ConfigService configService = XDAT.getConfigService();
@@ -53,4 +59,10 @@ public abstract class UploadAppletScreen extends SecureScreen {
         }
         return config;
     }
+
+    protected SerializerService getSerializer() {
+        return _serializer;
+    }
+
+    private final SerializerService _serializer;
 }
diff --git a/src/main/java/org/nrg/xnat/utils/SerializerService.java b/src/main/java/org/nrg/xnat/utils/SerializerService.java
new file mode 100644
index 0000000000000000000000000000000000000000..529f10b6777439e32150894975a3fb9f594621f2
--- /dev/null
+++ b/src/main/java/org/nrg/xnat/utils/SerializerService.java
@@ -0,0 +1,53 @@
+package org.nrg.xnat.utils;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.stereotype.Service;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import java.io.IOException;
+
+@Service
+public class SerializerService {
+    public JsonNode deserializeJson(final String json) throws IOException {
+        return _jsonObjectMapper.readTree(json);
+    }
+
+    public <T> T deserializeJson(final String json, final Class<T> clazz) throws IOException {
+        return _jsonObjectMapper.readValue(json, clazz);
+    }
+
+    public <T> T deserializeJson(final String json, final TypeReference<T> typeRef) throws IOException {
+        return _jsonObjectMapper.readValue(json, typeRef);
+    }
+
+    public <T> String toJson(final T instance) throws IOException {
+        return _jsonObjectMapper.writeValueAsString(instance);
+    }
+
+    public JsonNode deserializeYaml(final String yaml) throws IOException {
+        return _yamlObjectMapper.readTree(yaml);
+    }
+
+    public <T> T deserializeYaml(final String yaml, Class<T> clazz) throws IOException {
+        return _yamlObjectMapper.readValue(yaml, clazz);
+    }
+
+    public <T> T deserializeYaml(final String yaml, final TypeReference<T> typeRef) throws IOException {
+        return _yamlObjectMapper.readValue(yaml, typeRef);
+    }
+
+    public <T> String toYaml(final T instance) throws IOException {
+        return _yamlObjectMapper.writeValueAsString(instance);
+    }
+
+    @Inject
+    @Named("jsonObjectMapper")
+    private ObjectMapper _jsonObjectMapper;
+
+    @Inject
+    @Named("yamlObjectMapper")
+    private ObjectMapper _yamlObjectMapper;
+}
diff --git a/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml b/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f6e1311c8fde5ce996662230e772a31353b1c24e
--- /dev/null
+++ b/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml
@@ -0,0 +1,117 @@
+# Initial element declarations for the site admin user interface elements.
+siteId:
+    label: Site ID
+    type: text
+    id: site-id
+    description: Identifies your XNAT site.
+    placeholder: Enter your XNAT site ID...
+    url: /xapi/services/prefs/siteId/{siteId}
+    default: XNAT
+    validation:
+        required: true
+        type: xnat-id
+
+siteUrl:
+    label: Site Url
+    type: url
+    description: The root URL for the site. This is passed to external services.
+    placeholder: Enter the URL for your XNAT site...
+    value: https://cnda.wustl.edu
+    validation:
+        required: true
+
+siteDescriptionPage:
+    id: desc-page
+    label: Page
+    type: site.path
+    description: The page to display for the site description, e.g. /screens/site_description.vm.
+    value: /screens/site_description.vm
+    placeholder: Enter a page for your site description...
+    validation:
+        required: true
+
+siteDescriptionMarkdown:
+    id: desc-markdown
+    label: Text (Markdown)
+    type: markdown
+    tooltip: XNAT allows you to use GitHub-flavored Markdown to create and format your own site description. [&gt;&gt; View Tutorial](http://foobar)
+    description: Compose a site description without referencing a template or site page.
+    validation:
+        required: true
+
+siteDescription:
+    label: Site Description
+    type: composite
+    selection: radio
+    url: /data/services/prefs/{desc}
+    children:
+        ${siteDescriptionPage}
+        ${siteDescriptionMarkdown}
+
+landingPage:
+    label: Landing Page
+    type: site.path
+    description: The page to display when the user logs in.
+    value: /screens/QuickSearch.vm
+    placeholder: Enter the default landing page...
+    overrides:
+        target: homePage
+        type: checkbox
+        position: right
+        description: Use this as my home page.
+        hideTarget: false
+    validation:
+        required: true
+
+homePage:
+    label: Home Page
+    type: site.path
+    description: The page to display when the user clicks the home link.
+    value: /screens/AdminUsers.vm
+    placeholder: Enter the default home page...
+    validation:
+        required: true
+
+siteInfo:
+    label: Site Information
+    type: panel
+    controls:
+       ${siteId}
+       ${siteUrl}
+       ${siteDescription}
+       ${landingPage}
+       ${homePage}
+
+siteAdminEmail:
+    label: Site Admin Email
+    type: email
+    placeholder: Administrator email address...
+    url: /xapi/services/prefs/siteAdminEmail/{siteAdminEmail}
+    validation:
+        required: true
+
+adminInfo:
+    label: Admin Information
+    type: panel
+    controls:
+        ${siteAdminEmail}
+
+siteSetup:
+    label: Site Setup
+    type: tab
+    contents:
+        ${siteInfo}
+        ${adminInfo}
+
+xnatSetup:
+    label: XNAT Setup
+    type: tabGroup
+    tabs:
+        ${siteSetup}
+
+siteAdmin:
+    label: Administer XNAT
+    type: page
+    contains: tabs
+    contents:
+        ${xnatSetup}
diff --git a/src/main/webapp/META-INF/context.xml b/src/main/webapp/META-INF/context.xml
index 16bd2bec3ce56149a803754e2972b96d298abe37..b4c53f63c28668cc23be5f6c85c64b2487290da0 100644
--- a/src/main/webapp/META-INF/context.xml
+++ b/src/main/webapp/META-INF/context.xml
@@ -1,5 +1,5 @@
-<?xml version='1.0' encoding='utf-8'?>
-<Context antiResourceLocking="true">
+<?xml version="1.0" encoding="utf-8"?>
+<Context>
     <Loader className="org.apache.catalina.loader.VirtualWebappLoader" searchVirtualFirst="true" virtualClasspath="${xnat.home}/plugins/*.jar"/>
     <JarScanner scanAllDirectories="true" />
     <Parameter name="xnatHome" value="${xnat.home}"/>
diff --git a/src/main/webapp/WEB-INF/tags/spawner/layout.tag b/src/main/webapp/WEB-INF/tags/spawner/layout.tag
index 5e28cd9a34e305364548dab4f76d9faa4c974e4b..b096d29672bf34e178c3f841b9d897b312a33cfb 100644
--- a/src/main/webapp/WEB-INF/tags/spawner/layout.tag
+++ b/src/main/webapp/WEB-INF/tags/spawner/layout.tag
@@ -723,7 +723,7 @@
     <div id="layout_content">
         <!--BEGIN SCREEN CONTENT -->
 
-        <jsp:doBody scope="page"/>
+        <jsp:doBody/>
 
         <!-- END SCREEN CONTENT -->
     </div>
diff --git a/src/main/webapp/WEB-INF/views/spawner/element.jsp b/src/main/webapp/WEB-INF/views/spawner/element.jsp
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3954d9e9459d1388d87086a69dd661a5667135ac 100644
--- a/src/main/webapp/WEB-INF/views/spawner/element.jsp
+++ b/src/main/webapp/WEB-INF/views/spawner/element.jsp
@@ -0,0 +1,30 @@
+<%@ page contentType="text/html" pageEncoding="UTF-8" %>
+<%@ taglib prefix="sp" tagdir="/WEB-INF/tags/spawner" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<jsp:useBean id="elementId" scope="request" type="java.lang.String"/>
+
+<c:set var="title" value="Spawner Element: ${elementId}"/>
+<sp:layout title="${title}">
+    <h3 style="margin:0 0 15px 0;">${title}</h3>
+
+    <div style="margin:15px 0;max-width:696px;min-width:400px;">
+        Make your desired changes to the spawner element and click <b>Save</b> when completed.
+    </div>
+
+<script type="text/javascript">
+    var spawnerElement = $.ajax({
+        type : "GET",
+        url:serverRoot+"/xapi/spawner/${elementId}?XNAT_CSRF=" + window.csrfToken,
+        cache: false,
+        async: true,
+        context: this,
+        dataType: "yaml"
+    });
+    spawnerElement.done( function( data, textStatus, jqXHR ) {
+        if (typeof data.ResultSet !== "undefined" && typeof data.ResultSet.Result !== "undefined") {
+            alert(data);
+        }
+    });
+
+</script>
+</sp:layout>
\ No newline at end of file
diff --git a/src/main/webapp/WEB-INF/views/spawner/elements.jsp b/src/main/webapp/WEB-INF/views/spawner/elements.jsp
index ed05c3b0a19202b2d98b978aaa9e5496e7d20aa3..bea671ed2573041d7d256d8de89739360fd3d41e 100644
--- a/src/main/webapp/WEB-INF/views/spawner/elements.jsp
+++ b/src/main/webapp/WEB-INF/views/spawner/elements.jsp
@@ -3,13 +3,12 @@
 <%@ taglib prefix="sp" tagdir="/WEB-INF/tags/spawner" %>
 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 <jsp:useBean id="elements" scope="request" type="java.util.List"/>
-<jsp:useBean id="element" scope="request" type="org.nrg.xnat.spawner.entities.SpawnerElement"/>
 
 <sp:layout title="Spawner Elements">
     <h3 style="margin:0 0 15px 0;">Spawner Elements</h3>
 
     <div style="margin:15px 0;max-width:696px;min-width:400px;">
-        The Spawner is XNAT's system for managing dynamically configurable user interface elements.
+        The Spawner is XNAT's system for creating and updating dynamically configurable user interface elements.
     </div>
 
     <div class="yui-skin-sam">
@@ -105,14 +104,13 @@
                 <c:forEach var="element" items="${elements}">
                     <tr class="highlight events-list">
                         <td class="site-event-id">
-                                ${element.label}
+                            <a href="elements/${element.elementId}" class="edit-event" data-action="editEvent"
+                               title="edit existing event">${element.label}</a>
                         </td>
                         <td class="site-event-label">
                                 ${element.description}
                         </td>
                         <td class="actions" style="text-align:center;white-space:nowrap;">
-                            <a href="#!" class="edit-event" data-action="editEvent"
-                               title="edit existing event">edit</a>
                             <a href="#!" class="delete-event" data-action="deleteEvent"
                                title="delete existing event">delete</a>
                         </td>
diff --git a/src/main/webapp/resources/ui/skins/default/skin.props b/src/main/webapp/resources/ui/skins/default/skin.props
new file mode 100755
index 0000000000000000000000000000000000000000..59eecbe213ab4d3931579d7b71d4cc5e9161da8a
--- /dev/null
+++ b/src/main/webapp/resources/ui/skins/default/skin.props
@@ -0,0 +1,29 @@
+# These are the default properties  
+bgcolor = #ffffff 
+sansSerifFonts = verdana,geneva,helvetica 
+#formLabelColor = #b3cc99 
+#formFieldColor = #b3bb99 
+#labelColor = #b3cc99 
+#dataColor = #b3bb99 
+formLabelColor = #ffffff 
+formFieldColor = #ffffff 
+labelColor = #ffffff 
+dataColor = #ffffff 
+#vlink = #330066 
+#alink = #663399 
+vlink = #000000 
+alink = #000000  
+tableCellSpacing = 0 
+tableCellPadding = 0  
+menuColor = #000000  
+buttonAlignment = left 
+buttonColor = #DDDDDD  
+# Images alertImage = alert1.gif 
+logo = logo.jpg 
+poweredByImage = powered_by_tambora.gif 
+line = line.gif  
+#darkColor = #000088 
+#lightColor = #DDDDDD 
+darkColor = #000066 
+lightColor = #333399 
+tableColor = #AAAAAA   
\ No newline at end of file
diff --git a/src/main/webapp/resources/ui/skins/default/skin.txt b/src/main/webapp/resources/ui/skins/default/skin.txt
new file mode 100755
index 0000000000000000000000000000000000000000..081a8930bd907dee5d0de030c6eb6cc8d5746a34
Binary files /dev/null and b/src/main/webapp/resources/ui/skins/default/skin.txt differ