You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by de...@apache.org on 2017/10/31 13:12:38 UTC

svn commit: r1813881 - in /uima/uima-ducc/trunk: uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/ uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/ uima-ducc-database/src/main/java/org/apache/uima/ducc/database/ uima-ducc-...

Author: degenaro
Date: Tue Oct 31 13:12:38 2017
New Revision: 1813881

URL: http://svn.apache.org/viewvc?rev=1813881&view=rev
Log:
UIMA-5634 DUCC Orchestrator (OR) populate DB with Job and Managed Reservation specifications

Added:
    uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/
    uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/IDbDuccWorks.java   (with props)
    uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/ITypedProperties.java   (with props)
    uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/TypedProperties.java   (with props)
    uima/uima-ducc/trunk/uima-ducc-database/src/main/java/org/apache/uima/ducc/database/DbDuccWorks.java   (with props)
    uima/uima-ducc/trunk/uima-ducc-duccdocs/src/site/tex/duccbook/part2/webserver/json.tex
    uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/HelperSpecifications.java   (with props)
Modified:
    uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/CliBase.java
    uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccJobSubmit.java
    uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccManagedReservationSubmit.java
    uima/uima-ducc/trunk/uima-ducc-database/src/main/java/org/apache/uima/ducc/database/DbCreate.java
    uima/uima-ducc/trunk/uima-ducc-duccdocs/src/site/tex/duccbook/part2/webserver.tex
    uima/uima-ducc/trunk/uima-ducc-orchestrator/src/main/java/org/apache/uima/ducc/orchestrator/OrchestratorComponent.java
    uima/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/cli/SpecificationProperties.java
    uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandler.java
    uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandlerJsonFormat.java
    uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/Helper.java
    uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/utils/HandlersHelper.java

Modified: uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/CliBase.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/CliBase.java?rev=1813881&r1=1813880&r2=1813881&view=diff
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/CliBase.java (original)
+++ uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/CliBase.java Tue Oct 31 13:12:38 2017
@@ -480,9 +480,27 @@ public abstract class CliBase
         return sb.toString();
     }
 
+    /*
+     * Undocumented feature:
+     * Existence of environment variable DUCC_SAVE_SPECIFICATION 
+     * will result in specification written to filesystem, 
+     * otherwise not.  Orchestrator writes specifications to DB.
+     */
+    private boolean isSavable() {
+    	boolean retVal = false;
+    	String savespec = System.getenv("DUCC_SAVE_SPECIFICATION");
+    	if ( savespec != null ) {
+    		retVal = true;
+    	}
+    	return retVal;
+    }
+    
     void saveSpec(String name, DuccProperties props)
         throws Exception
     {
+    	if ( ! isSavable() ) {
+    		return;
+    	}
         String directory = props.getProperty("log_directory") + File.separator + friendlyId;
         String fileName = directory + File.separator + name;
         File f = new File(directory);

Modified: uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccJobSubmit.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccJobSubmit.java?rev=1813881&r1=1813880&r2=1813881&view=diff
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccJobSubmit.java (original)
+++ uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccJobSubmit.java Tue Oct 31 13:12:38 2017
@@ -19,6 +19,7 @@
 package org.apache.uima.ducc.cli;
 
 import java.util.ArrayList;
+import java.util.Map.Entry;
 import java.util.Properties;
 
 import org.apache.uima.ducc.cli.aio.AllInOneLauncher;
@@ -334,7 +335,15 @@ public class DuccJobSubmit
 
         // Warn if Xmx value is too large and may cause swapping
         check_heap_size(UiOption.ProcessJvmArgs.pname());
-
+        
+        /*
+         * keep list of user provided properties for WS display: user vs. system
+         */
+        for(Entry<Object, Object> entry : userSpecifiedProperties.entrySet()) {
+        	String key = (String) entry.getKey();
+        	jobRequestProperties.addUserProvided(key);
+        }
+        
         SubmitJobDuccEvent      submitJobDuccEvent      = new SubmitJobDuccEvent(jobRequestProperties, CliVersion.getVersion());
         SubmitJobReplyDuccEvent submitJobReplyDuccEvent = null;
         try {

Modified: uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccManagedReservationSubmit.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccManagedReservationSubmit.java?rev=1813881&r1=1813880&r2=1813881&view=diff
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccManagedReservationSubmit.java (original)
+++ uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccManagedReservationSubmit.java Tue Oct 31 13:12:38 2017
@@ -19,6 +19,7 @@
 package org.apache.uima.ducc.cli;
 
 import java.util.ArrayList;
+import java.util.Map.Entry;
 import java.util.Properties;
 
 import org.apache.uima.ducc.common.utils.DuccSchedulerClasses;
@@ -176,11 +177,19 @@ public class DuccManagedReservationSubmi
         check_heap_size(UiOption.ProcessExecutableArgs.pname());
 
         // Create a copy to be saved later without these 3 "ducclet" properties required by DUCC
-        ServiceRequestProperties serviceProperties = (ServiceRequestProperties)serviceRequestProperties.clone();
+        ServiceRequestProperties userSpecifiedProperties = (ServiceRequestProperties)serviceRequestProperties.clone();
         serviceRequestProperties.setProperty(UiOption.ProcessPipelineCount.pname(), "1");
         serviceRequestProperties.setProperty(UiOption.ProcessDeploymentsMax.pname(), "1");
         serviceRequestProperties.setProperty(UiOption.ServiceTypeOther.pname(), "");
 
+        /*
+         * keep list of user provided properties for WS display: user vs. system
+         */
+        for(Entry<Object, Object> entry : userSpecifiedProperties.entrySet()) {
+        	String key = (String) entry.getKey();
+        	serviceRequestProperties.addUserProvided(key);
+        }
+        
         SubmitServiceDuccEvent ev = new SubmitServiceDuccEvent(serviceRequestProperties, CliVersion.getVersion());
         SubmitServiceReplyDuccEvent reply = null;
 
@@ -195,7 +204,7 @@ public class DuccManagedReservationSubmi
          */
         boolean rc = extractReply(reply);
 		if (rc) {
-			saveSpec(DuccUiConstants.managed_reservation_properties, serviceProperties);
+			saveSpec(DuccUiConstants.managed_reservation_properties, userSpecifiedProperties);
 			startMonitors(true, DuccContext.ManagedReservation);       // starts conditionally, based on job spec and console listener present
         }
 

Added: uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/IDbDuccWorks.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/IDbDuccWorks.java?rev=1813881&view=auto
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/IDbDuccWorks.java (added)
+++ uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/IDbDuccWorks.java Tue Oct 31 13:12:38 2017
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+*/
+package org.apache.uima.ducc.common.persistence.or;
+
+import org.apache.uima.ducc.common.persistence.IDbProperty;
+import org.apache.uima.ducc.common.utils.DuccLogger;
+
+public interface IDbDuccWorks {
+
+	enum DbDuccWorks implements IDbProperty {
+		TABLE_NAME {
+			public String pname() {
+				return "duccworks";
+			}
+
+			public Type type() {
+				return Type.String;
+			}
+
+			public boolean isPrivate() {
+				return true;
+			}
+
+			public boolean isMeta() {
+				return true;
+			}
+		},
+		// The order of the primary keys is important here as the Db assigns
+		// semantics to the first key in a compound PK
+		type { 
+			// value = { "job", "reservation", "service", ... }
+			public boolean isPrimaryKey() {
+				return true;
+			}
+		},
+		ducc_id {
+			public Type type() {
+				return Type.Long;
+			}
+			public boolean isPrimaryKey() {
+				return true;
+			}
+		},
+		specification {
+			// json data = map: { user: Properties }, { system: Properties }
+		},
+
+		;
+		public String pname() {
+			return name();
+		}
+
+		public Type type() {
+			return Type.String;
+		}
+
+		public boolean isPrimaryKey() {
+			return false;
+		}
+
+		public boolean isPrivate() {
+			return false;
+		}
+
+		public boolean isMeta() {
+			return false;
+		}
+
+		public boolean isIndex() {
+			return false;
+		}
+
+		public String columnName() {
+			return pname();
+		}
+	}
+
+	/**
+	 * Establish a logger and anything else the persistence may need.
+	 * 
+	 * @param logger
+	 *            This is the logger to be used. It is usually the same logger
+	 *            as the client of persistence, e.g. org.apache.uima.ducc.or.
+	 *            The implementor is required to adjust itself to use this
+	 *            logger to insure messages are logged into the right log.
+	 */
+	public void init(DuccLogger logger) throws Exception;
+
+	/**
+	 * create table(s)
+	 */
+	public void dbInit() throws Exception;
+	
+	/**
+	 * insert or update specification
+	 */
+	public void upsertSpecification(String type, long id, ITypedProperties typedProperties)
+			throws Exception;
+	
+	/**
+	 * fetch specification
+	 */
+	public ITypedProperties fetchSpecification(String type, long id) throws Exception;
+	
+}

Propchange: uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/IDbDuccWorks.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/IDbDuccWorks.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/ITypedProperties.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/ITypedProperties.java?rev=1813881&view=auto
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/ITypedProperties.java (added)
+++ uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/ITypedProperties.java Tue Oct 31 13:12:38 2017
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+*/
+package org.apache.uima.ducc.common.persistence.or;
+
+import java.util.Map;
+import java.util.Properties;
+
+public interface ITypedProperties {
+
+	public static enum SpecificationType { Job, ManagedReservation, Reservation, Service };
+	
+	public static enum PropertyType { user, system };
+	
+	public void add(String type, Object name, Object value);
+	public void add(String type, Properties properties);
+	public Properties remove(String type);
+	public Object remove(String type, Object name);
+	public Properties queryType(String type);
+	public Map<String,Properties> getMap();
+}

Propchange: uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/ITypedProperties.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/ITypedProperties.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/TypedProperties.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/TypedProperties.java?rev=1813881&view=auto
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/TypedProperties.java (added)
+++ uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/TypedProperties.java Tue Oct 31 13:12:38 2017
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+*/
+package org.apache.uima.ducc.common.persistence.or;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+public class TypedProperties implements ITypedProperties {
+	
+	private HashMap<String,Properties> map = new HashMap<String,Properties>();
+	
+	@Override
+	public void add(String type, Object name, Object value) {
+		if((type != null) && (name != null) && (value != null)) {
+			if(!map.containsKey(type)) {
+				map.put(type, new Properties());
+			}
+			Properties properties = map.get(type);
+			properties.put(name, value);
+		}
+	}
+	
+	@Override
+	public void add(String type, Properties properties) {
+		if((type != null) && (properties != null)) {
+			for(Entry<Object, Object> property : properties.entrySet()) {
+				add(type, property.getKey(), property.getValue());
+			}
+		}
+	}
+	
+	@Override
+	public Properties remove(String type) {
+		Properties retVal = null;
+		if(type != null) {
+			if(!map.containsKey(type)) {
+				retVal = map.remove(type);
+			}
+		}
+		return retVal;
+	}
+	
+	@Override
+	public Object remove(String type, Object name) {
+		Object retVal = null;
+		if((type != null) && (name != null)) {
+			if(!map.containsKey(type)) {
+				Properties properties = map.get(type);
+				if(properties.containsKey(name)) {
+					retVal = properties.remove(name);
+				}
+			}
+		}
+		return retVal;
+	}
+	
+	@Override
+	public Properties queryType(String type) {
+		Properties properties = null;
+		if(type != null) {
+			properties = map.get(type);
+		}
+		return properties;
+	}
+
+	@Override
+	public Map<String, Properties> getMap() {
+		return map;
+	}
+}

Propchange: uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/TypedProperties.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/persistence/or/TypedProperties.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: uima/uima-ducc/trunk/uima-ducc-database/src/main/java/org/apache/uima/ducc/database/DbCreate.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-database/src/main/java/org/apache/uima/ducc/database/DbCreate.java?rev=1813881&r1=1813880&r2=1813881&view=diff
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-database/src/main/java/org/apache/uima/ducc/database/DbCreate.java (original)
+++ uima/uima-ducc/trunk/uima-ducc-database/src/main/java/org/apache/uima/ducc/database/DbCreate.java Tue Oct 31 13:12:38 2017
@@ -229,7 +229,23 @@ public class DbCreate
                 doLog(methodName, "EXECUTE STATEMENT:", s.toString());
                 session.execute(s);
             }
-
+            
+            /*
+             * The following table for specifications is created by Orchestrator
+             * at boot time, if not already present.  This additional table was 
+             * not part of the DB in versions DUCC 2.2.1 and earlier.  In this
+             * fashion, both migrated systems as well as fresh installs are able
+             * to utilize this table without the need for invocation of 
+             * ducc_post_install.  The commented-out code below is thus for
+             * documentation purposes only.
+             * 
+            List<SimpleStatement>specificationsSchema = DbDuccWorks.mkSchema();
+            for ( SimpleStatement s : specificationsSchema ) {
+                doLog(methodName, "EXECUTE STATEMENT:", s.toString());
+                session.execute(s);
+            }
+			*/
+            
         } catch ( Exception e ) {
             doLog(methodName, "Cannot create schema:", e);
         }

Added: uima/uima-ducc/trunk/uima-ducc-database/src/main/java/org/apache/uima/ducc/database/DbDuccWorks.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-database/src/main/java/org/apache/uima/ducc/database/DbDuccWorks.java?rev=1813881&view=auto
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-database/src/main/java/org/apache/uima/ducc/database/DbDuccWorks.java (added)
+++ uima/uima-ducc/trunk/uima-ducc-database/src/main/java/org/apache/uima/ducc/database/DbDuccWorks.java Tue Oct 31 13:12:38 2017
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+*/
+package org.apache.uima.ducc.database;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.uima.ducc.common.persistence.or.IDbDuccWorks;
+import org.apache.uima.ducc.common.persistence.or.ITypedProperties;
+import org.apache.uima.ducc.common.persistence.or.TypedProperties;
+import org.apache.uima.ducc.common.utils.DuccLogger;
+import org.apache.uima.ducc.common.utils.id.DuccId;
+
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.datastax.driver.core.SimpleStatement;
+import com.datastax.driver.core.exceptions.NoHostAvailableException;
+import com.google.gson.Gson;
+
+public class DbDuccWorks implements IDbDuccWorks {
+	
+	/*
+	 * table comprising specifications for Jobs, Managed Reservations
+	 */
+	private static String DUCC_WORKS_TABLE = DbDuccWorks.TABLE_NAME.pname();
+
+	private static String COL_TYPE = DbDuccWorks.type.columnName();
+	private static String COL_DUCC_ID = DbDuccWorks.ducc_id.columnName();
+	private static String COL_SPECIFICATION = DbDuccWorks.specification.columnName();
+	
+	private DuccLogger logger = null;
+	private DbManager dbManager = null;
+
+	private Gson gson = new Gson();
+	
+	private DuccId jobid = null;
+	
+	public DbDuccWorks(DuccLogger duccLogger) throws Exception {
+		init(duccLogger);
+	}
+	
+	/*
+	 * connect to DB
+	 */
+	private boolean init(String dburl) throws Exception {
+		String methodName = "init";
+		boolean ret = false;
+		while (true) {
+			try {
+				dbManager = new DbManager(dburl, logger);
+				dbManager.init();
+				ret = true;
+				break;
+			} catch (NoHostAvailableException e) {
+				logger.error(methodName, null,
+						"Cannot contact database.  Retrying in 5 seconds.");
+				Thread.sleep(5000);
+			} catch (Exception e) {
+				logger.error(methodName, null,
+						"Errors contacting database.  No connetion made.");
+				logger.error(methodName, null, e);
+				ret = false;
+				break;
+			}
+		}
+		return ret;
+	}
+
+	/*
+	 * CQL to create:
+	 *   Specifications table, keyed by type (Job, ManagedReservation) + DuccId
+	 */
+	protected static List<SimpleStatement> mkSchema() throws Exception {
+		List<SimpleStatement> ret = new ArrayList<SimpleStatement>();
+
+		StringBuffer buf = new StringBuffer("CREATE TABLE IF NOT EXISTS "
+				+ DUCC_WORKS_TABLE + " (");
+		buf.append(DbUtil.mkSchema(DbDuccWorks.values()));
+		buf.append(")");
+		ret.add(new SimpleStatement(buf.toString()));
+		List<String> indexes = DbUtil.mkIndices(DbDuccWorks.values(),
+				DUCC_WORKS_TABLE);
+		for (String s : indexes) {
+			ret.add(new SimpleStatement(s));
+		}
+
+		return ret;
+	}
+
+	/**
+	 * Create tables(s)
+	 */
+	public void dbInit() throws Exception {
+		String location = "dbInit";
+		try {
+			List<SimpleStatement>specificationsSchema = mkSchema();
+			DbHandle h = dbManager.open();
+	        for ( SimpleStatement s : specificationsSchema ) {
+	            logger.info(location, jobid, "EXECUTE STATEMENT:"+s.toString());
+	            h.execute(s);
+	        }
+		}
+		catch(Exception e) {
+			logger.error(location, jobid, e);
+			throw e;
+		}
+	}
+	
+	/**
+	 * Prepare for DB access
+	 */
+	@Override
+	public void init(DuccLogger duccLogger) throws Exception {
+		 this.logger = duccLogger;
+	     String dbUrl = System.getProperty(DbManager.URL_PROPERTY);
+	     init(dbUrl);
+	}
+
+	/**
+	 * Add or update a specification of type Job or ManagedReservation
+	 * 
+	 * SPECIFICATION data is kept in DB as JSON comprising:
+	 * { map: system: { k1:v1, k2:v2,... }, user: { k1:v1, k2:v2,... } } 
+	 */
+	@Override
+	public void upsertSpecification(String type, long id, ITypedProperties properties) throws Exception {
+		String location = "upsertSpecification";
+		String gsonString = null;
+		try {
+			gsonString = gson.toJson(properties);
+			String table = DUCC_WORKS_TABLE;
+			String c0 = COL_SPECIFICATION+"="+"'"+gsonString+"'";
+			String c1 = COL_TYPE+"="+"'"+type+"'";
+			String c2 = COL_DUCC_ID+"="+id;
+	        String cql = "UPDATE "+table+" SET "+c0+" WHERE "+c1+" AND "+c2;
+	        logger.debug(location, jobid, cql);
+	        DbHandle h = dbManager.open();
+	        h.execute(cql);
+		}
+		catch(Exception e) {
+			DuccId duccid = new DuccId(id);
+			String text = "type="+type+" "+"gson="+gsonString;
+			logger.error(location, duccid, text ,e);
+			throw e;
+		}
+	}
+	
+	/**
+	 * Retrieve a specification of type Job or ManagedReservation
+	 */
+	@Override
+	public ITypedProperties fetchSpecification(String type, long id) throws Exception {
+		String location = "fetchSpecification";
+		ITypedProperties properties = null;
+		try {
+			String table = DUCC_WORKS_TABLE;
+			String c1 = COL_TYPE+"="+"'"+type+"'";
+			String c2 = COL_DUCC_ID+"="+id;
+	        String cql = "SELECT * FROM "+table+" WHERE "+c1+" AND "+c2;
+	        logger.debug(location, jobid, cql);
+	        DbHandle h = dbManager.open();
+	        ResultSet rs = h.execute(cql);
+	        for ( Row r : rs ) {
+	            String gsonString = r.getString(COL_SPECIFICATION);
+	            logger.debug(location, jobid, gsonString);
+	            properties = (ITypedProperties) gson.fromJson(gsonString, TypedProperties.class);
+	        }
+		}
+		catch(Exception e) {
+			DuccId duccid = new DuccId(id);
+			String text = "type="+type;
+			logger.error(location, duccid, text ,e);
+			throw e;
+		}
+        return properties;
+	}
+
+}

Propchange: uima/uima-ducc/trunk/uima-ducc-database/src/main/java/org/apache/uima/ducc/database/DbDuccWorks.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: uima/uima-ducc/trunk/uima-ducc-database/src/main/java/org/apache/uima/ducc/database/DbDuccWorks.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: uima/uima-ducc/trunk/uima-ducc-duccdocs/src/site/tex/duccbook/part2/webserver.tex
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-duccdocs/src/site/tex/duccbook/part2/webserver.tex?rev=1813881&r1=1813880&r2=1813881&view=diff
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-duccdocs/src/site/tex/duccbook/part2/webserver.tex (original)
+++ uima/uima-ducc/trunk/uima-ducc-duccdocs/src/site/tex/duccbook/part2/webserver.tex Tue Oct 31 13:12:38 2017
@@ -177,6 +177,10 @@
 	Logs, files and other data are accessed by the Linux permissions of the 
 	logged-in user.
 	
+	Specifications for Jobs and Managed Reservations are kept in the database.  
+	Read access is granted for a logged-in user
+	via {\em site-security}-directory/.ducc/db.access file read permission.
+	
 	For the Services Registry in particular, the following attributes give 
 	the Web Server browsing user read or write access:
 	
@@ -243,3 +247,10 @@
       \HCode{<a name='DUCC_WS_Viz'></a>}
       \fi
       \input{part2/webserver/viz.tex}
+      
+      % Create well-known link to this spot for HTML version
+      \ifpdf
+      \else
+      \HCode{<a name='DUCC_WS_JSON'></a>}
+      \fi
+      \input{part2/webserver/json.tex}

Added: uima/uima-ducc/trunk/uima-ducc-duccdocs/src/site/tex/duccbook/part2/webserver/json.tex
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-duccdocs/src/site/tex/duccbook/part2/webserver/json.tex?rev=1813881&view=auto
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-duccdocs/src/site/tex/duccbook/part2/webserver/json.tex (added)
+++ uima/uima-ducc/trunk/uima-ducc-duccdocs/src/site/tex/duccbook/part2/webserver/json.tex Tue Oct 31 13:12:38 2017
@@ -0,0 +1,42 @@
+% 
+% Licensed to the Apache Software Foundation (ASF) under one
+% or more contributor license agreements.  See the NOTICE file
+% distributed with this work for additional information
+% regarding copyright ownership.  The ASF licenses this file
+% to you under the Apache License, Version 2.0 (the
+% "License"); you may not use this file except in compliance
+% with the License.  You may obtain a copy of the License at
+% 
+%   http://www.apache.org/licenses/LICENSE-2.0
+% 
+% Unless required by applicable law or agreed to in writing,
+% software distributed under the License is distributed on an
+% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+% KIND, either express or implied.  See the License for the
+% specific language governing permissions and limitations
+% under the License.
+% 
+
+    \section{JSON}
+    \label{sec:ws.JSON}
+    
+    The following list comprises requests honored for JSON data:
+    
+    \begin{itemize}
+       \item /ducc-servlet/json-format-job-specification?id={\em nnnnnn}
+       
+       Result is JSON comprising {\em system} and {\em user} properties sets, with format: 
+       \begin{verbatim}
+       {
+       "system":{"user":"degenaro","process_initialization_failures_cap":"99,...}
+       "user":{"scheduling_class":"normal",...}
+       }
+	   \end{verbatim}
+		
+       \item /ducc-servlet/json-format-managed-reservation-specification?id={\em nnnnnn}
+       
+       Result is JSON comprising {\em system} and {\em user} properties sets, with format similar
+       to  the above.
+       
+    \end{itemize}
+

Modified: uima/uima-ducc/trunk/uima-ducc-orchestrator/src/main/java/org/apache/uima/ducc/orchestrator/OrchestratorComponent.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-orchestrator/src/main/java/org/apache/uima/ducc/orchestrator/OrchestratorComponent.java?rev=1813881&r1=1813880&r2=1813881&view=diff
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-orchestrator/src/main/java/org/apache/uima/ducc/orchestrator/OrchestratorComponent.java (original)
+++ uima/uima-ducc/trunk/uima-ducc-orchestrator/src/main/java/org/apache/uima/ducc/orchestrator/OrchestratorComponent.java Tue Oct 31 13:12:38 2017
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Properties;
 
 import org.apache.camel.CamelContext;
@@ -40,6 +41,8 @@ import org.apache.uima.ducc.common.crypt
 import org.apache.uima.ducc.common.internationalization.Messages;
 import org.apache.uima.ducc.common.main.DuccRmAdmin;
 import org.apache.uima.ducc.common.main.DuccService;
+import org.apache.uima.ducc.common.persistence.or.IDbDuccWorks;
+import org.apache.uima.ducc.common.persistence.or.TypedProperties;
 import org.apache.uima.ducc.common.system.SystemState;
 import org.apache.uima.ducc.common.utils.DuccLogger;
 import org.apache.uima.ducc.common.utils.DuccLoggerComponents;
@@ -47,6 +50,7 @@ import org.apache.uima.ducc.common.utils
 import org.apache.uima.ducc.common.utils.IDuccLoggerComponents;
 import org.apache.uima.ducc.common.utils.TimeStamp;
 import org.apache.uima.ducc.common.utils.id.DuccId;
+import org.apache.uima.ducc.database.DbDuccWorks;
 import org.apache.uima.ducc.orchestrator.OrchestratorConstants.StartType;
 import org.apache.uima.ducc.orchestrator.authentication.DuccWebAdministrators;
 import org.apache.uima.ducc.orchestrator.exceptions.ResourceUnavailableForJobDriverException;
@@ -75,6 +79,7 @@ import org.apache.uima.ducc.transport.ev
 import org.apache.uima.ducc.transport.event.cli.JobRequestProperties;
 import org.apache.uima.ducc.transport.event.cli.ReservationReplyProperties;
 import org.apache.uima.ducc.transport.event.cli.ReservationRequestProperties;
+import org.apache.uima.ducc.transport.event.cli.ServiceRequestProperties;
 import org.apache.uima.ducc.transport.event.cli.SpecificationProperties;
 import org.apache.uima.ducc.transport.event.common.DuccProcessMap;
 import org.apache.uima.ducc.transport.event.common.DuccWorkJob;
@@ -120,8 +125,25 @@ implements Orchestrator {
 	private StateJobAccounting stateJobAccounting = StateJobAccounting.getInstance();
 	private DuccPropertiesResolver dpr = DuccPropertiesResolver.getInstance();
 	
+	private IDbDuccWorks dbDuccWorks = null;
+	
 	public OrchestratorComponent(CamelContext context) {
 		super("Orchestrator", context);
+		init();
+	}
+	
+	/*
+	 * Initialize DB access, and create table(s) if not already present
+	 */
+	private void init() {
+		String location = "init";
+		try {
+			dbDuccWorks = new DbDuccWorks(logger);
+			dbDuccWorks.dbInit();
+		}
+		catch(Exception e) {
+			logger.error(location, jobid, e);
+		}
 	}
 	
 	public void onDuccAdminKillEvent(DuccAdminEvent event) throws Exception {
@@ -605,6 +627,24 @@ implements Orchestrator {
 						// prepare for reply to submitter
 						properties.put(JobRequestProperties.key_id, duccWorkJob.getId());
 						duccEvent.setProperties(properties);
+						// save specification to DB
+						TypedProperties tp = new TypedProperties();
+						for(Entry<Object, Object> entry : properties.entrySet()) {
+							String name = (String) entry.getKey();
+							if(name.equals("signature")) {
+								// skip it
+							}
+							else {
+								String type = TypedProperties.PropertyType.system.name();
+								if(properties.isUserProvided(name)) {
+									type = TypedProperties.PropertyType.user.name();
+								}
+								tp.add(type, entry.getKey(), entry.getValue());
+							}
+						}
+						String specificationType = TypedProperties.SpecificationType.Job.name();
+						Long id = duccWorkJob.getDuccId().getFriendly();
+						dbDuccWorks.upsertSpecification(specificationType, id, tp);
 					}
 					catch(ResourceUnavailableForJobDriverException e) {
 						String error_message = messages.fetch(" type=system error, text=job driver node unavailable.");
@@ -969,6 +1009,45 @@ implements Orchestrator {
 					// prepare for reply to submitter
 					properties.put(JobRequestProperties.key_id, duccWorkJob.getId());
 					duccEvent.setProperties(properties);
+					// save specification to DB
+					TypedProperties tp = new TypedProperties();
+					for(Entry<Object, Object> entry : properties.entrySet()) {
+						String name = (String) entry.getKey();
+						if(name.equals("signature")) {
+							// skip it
+						}
+						else {
+							String type = TypedProperties.PropertyType.system.name();
+							if(properties.isUserProvided(name)) {
+								type = TypedProperties.PropertyType.user.name();
+							}
+							tp.add(type, entry.getKey(), entry.getValue());
+						}
+					}
+					long id = duccWorkJob.getDuccId().getFriendly();
+					if(properties.containsKey(ServiceRequestProperties.key_service_type_other)) {
+						String specificationType = TypedProperties.SpecificationType.ManagedReservation.name();
+						dbDuccWorks.upsertSpecification(specificationType, id, tp);
+						/* 
+						 * save managed reservation specification instances
+						 */
+						logger.trace(methodName, duccWorkJob.getDuccId(), "type="+specificationType );
+					}
+					else {
+						String specificationType = TypedProperties.SpecificationType.Service.name();
+						long instance_id = 0;
+						try {
+							String value = properties.getProperty("id");
+							instance_id = Long.valueOf(value);
+						}
+						catch(Exception e) {
+							// oh well...
+						}
+						/* 
+						 * do not save service specification instances
+						 */
+						logger.trace(methodName, duccWorkJob.getDuccId(), "type="+specificationType, "instance_id="+instance_id );
+					}
 				}
 				else {
 					logger.info(methodName, null, messages.fetch("TODO")+" prepare error reply");

Modified: uima/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/cli/SpecificationProperties.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/cli/SpecificationProperties.java?rev=1813881&r1=1813880&r2=1813881&view=diff
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/cli/SpecificationProperties.java (original)
+++ uima/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/cli/SpecificationProperties.java Tue Oct 31 13:12:38 2017
@@ -19,6 +19,8 @@
 package org.apache.uima.ducc.transport.event.cli;
 
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.apache.uima.ducc.common.utils.DuccProperties;
 
@@ -52,6 +54,13 @@ public class SpecificationProperties ext
 	public static String key_reason = "reason";
 	
 	/*
+	 * A list keys for which the "user" provided the value.
+	 * The values for keys not listed here were therefore
+	 * provided by "system" (aka DUCC).
+	 */
+	private List<String> userProvided = new ArrayList<String>();
+	
+	/*
 	 * Disable place-holder expansion in DuccProperties.getProperty as CLI does it when processing the options,
 	 * and any unresolved ones must be left asis, e.g. DUCC_SERVICE_INSTANCE
 	 * All CLI apis should use this or a subclass of it.
@@ -59,4 +68,47 @@ public class SpecificationProperties ext
 	public SpecificationProperties() {
 		resolvePlaceholders = false;
 	}
+	
+	/*
+	 * <convenience methods to manage "userProvided" list>
+	 */
+	public boolean isUserProvided(String name) {
+		boolean retVal = false;
+		try {
+			if(name != null) {
+				retVal = userProvided.contains(name);
+			}
+		}
+		catch(Exception e) {
+			// legacy object
+		}
+		return retVal;
+	}
+	public void addUserProvided(String name) {
+		try {
+			if(name != null) {
+				if(!isUserProvided(name)) {
+					userProvided.add(name);
+				}
+			}
+		}
+		catch(Exception e) {
+			// legacy object
+		}
+	}
+	public void delUserProvided(String name) {
+		try {
+			if(name != null) {
+				if(isUserProvided(name)) {
+					userProvided.remove(name);
+				}
+			}
+		}
+		catch(Exception e) {
+			// legacy object
+		}
+	}
+	/*
+	 * </convenience methods to manage "userProvided" list>
+	 */
 }

Modified: uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandler.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandler.java?rev=1813881&r1=1813880&r2=1813881&view=diff
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandler.java (original)
+++ uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandler.java Tue Oct 31 13:12:38 2017
@@ -43,7 +43,6 @@ import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.uima.ducc.cli.DuccUiConstants;
 import org.apache.uima.ducc.common.CancelReasons.CancelReason;
 import org.apache.uima.ducc.common.NodeConfiguration;
 import org.apache.uima.ducc.common.SizeBytes;
@@ -101,13 +100,14 @@ import org.apache.uima.ducc.ws.registry.
 import org.apache.uima.ducc.ws.registry.sort.IServiceAdapter;
 import org.apache.uima.ducc.ws.registry.sort.ServicesSortCache;
 import org.apache.uima.ducc.ws.server.Helper.AllocationType;
+import org.apache.uima.ducc.ws.server.HelperSpecifications.PType;
 import org.apache.uima.ducc.ws.server.IWebMonitor.MonitorType;
 import org.apache.uima.ducc.ws.sort.JobDetailsProcesses;
 import org.apache.uima.ducc.ws.types.NodeId;
 import org.apache.uima.ducc.ws.utils.FormatHelper;
 import org.apache.uima.ducc.ws.utils.FormatHelper.Precision;
 import org.apache.uima.ducc.ws.utils.HandlersHelper;
-import org.apache.uima.ducc.ws.utils.HandlersHelper.ServiceAuthorization;
+import org.apache.uima.ducc.ws.utils.HandlersHelper.DataAccessPermission;
 import org.apache.uima.ducc.ws.utils.UrlHelper;
 import org.apache.uima.ducc.ws.utils.alien.AlienWorkItemStateReader;
 import org.apache.uima.ducc.ws.utils.alien.EffectiveUser;
@@ -131,7 +131,7 @@ public class DuccHandler extends DuccAbs
 
 	private enum DetailsType { Job, Reservation, Service };
 
-
+	private HelperSpecifications helperSpecifications = HelperSpecifications.getInstance();
 	private DuccAuthenticator duccAuthenticator = DuccAuthenticator.getInstance();
 
 	private String duccVersion						= duccContext+"/version";
@@ -1279,39 +1279,11 @@ public class DuccHandler extends DuccAbs
 	}
 
 	private DuccWorkJob getJob(String jobNo) {
-		DuccWorkJob job = null;
-		IDuccWorkMap duccWorkMap = DuccData.getInstance().get();
-		if(duccWorkMap.getJobKeySet().size()> 0) {
-			Iterator<DuccId> iterator = null;
-			iterator = duccWorkMap.getJobKeySet().iterator();
-			while(iterator.hasNext()) {
-				DuccId jobId = iterator.next();
-				String fid = ""+jobId.getFriendly();
-				if(jobNo.equals(fid)) {
-					job = (DuccWorkJob) duccWorkMap.findDuccWork(jobId);
-					break;
-				}
-			}
-		}
-		return job;
+		return Helper.getJob(jobNo);
 	}
 
 	private DuccWorkJob getManagedReservation(String reservationNo) {
-		DuccWorkJob managedReservation = null;
-		IDuccWorkMap duccWorkMap = DuccData.getInstance().get();
-		if(duccWorkMap.getServiceKeySet().size()> 0) {
-			Iterator<DuccId> iterator = null;
-			iterator = duccWorkMap.getServiceKeySet().iterator();
-			while(iterator.hasNext()) {
-				DuccId jobId = iterator.next();
-				String fid = ""+jobId.getFriendly();
-				if(reservationNo.equals(fid)) {
-					managedReservation = (DuccWorkJob) duccWorkMap.findDuccWork(jobId);
-					break;
-				}
-			}
-		}
-		return managedReservation;
+		return Helper.getManagedReservation(reservationNo);
 	}
 
 	private long getAdjustedTime(long time, IDuccWorkJob job) {
@@ -1739,19 +1711,28 @@ public class DuccHandler extends DuccAbs
 		String methodName = "handleDuccServletJobSpecificationData";
 		duccLogger.trace(methodName, null, messages.fetch("enter"));
 		String jobNo = request.getParameter("id");
-		DuccWorkJob work = getJob(jobNo);
-		if(work != null) {
-			EffectiveUser eu = EffectiveUser.create(request);
-	        String path = work.getUserLogDir() + DuccUiConstants.job_specification_properties;
-	        Properties usProperties;
-	        Properties properties;
-	        try {
-	            usProperties = DuccFile.getUserSpecifiedProperties(eu, work);
-	            properties = DuccFile.getProperties(eu, path);
-	        } catch (Throwable e) {
-	            throw new IOException(e);
-	        }
-			processSpecificationData(request, response, usProperties, properties, null);
+		DuccWorkJob dwj = getJob(jobNo);
+		String resOwner = dwj.getStandardInfo().getUser();
+		EffectiveUser eu = EffectiveUser.create(request);
+		String reqUser = eu.get();
+		Map<String,Properties> map = null;
+		if(HandlersHelper.isResourceAuthorized(resOwner, reqUser)) {
+			map = helperSpecifications.getJobSpecificationProperties(dwj, eu);
+		}
+		if(map != null) {
+			Properties propertiesUser = map.get(PType.user.name());
+			Properties propertiesSystem = map.get(PType.all.name());
+			int usize = -1;
+			if(propertiesUser != null) {
+				usize = propertiesUser.size();
+			}
+			duccLogger.debug(methodName, jobid, "user="+usize);
+			int ssize = -1;
+			if(propertiesSystem != null) {
+				ssize = propertiesSystem.size();
+			}
+			duccLogger.debug(methodName, jobid, "system="+ssize);
+			processSpecificationData(request, response, propertiesUser, propertiesSystem, null);
 		}
 		else {
 			String msg = "(data not found)";
@@ -2257,20 +2238,35 @@ public class DuccHandler extends DuccAbs
 	{
 		String methodName = "handleDuccServletReservationSpecificationData";
 		duccLogger.trace(methodName, null, messages.fetch("enter"));
-		String reservationNo = request.getParameter("id");
-		DuccWorkJob work = getManagedReservation(reservationNo);
-
-        EffectiveUser eu = EffectiveUser.create(request);
-        String path = work.getUserLogDir() + DuccUiConstants.managed_reservation_properties;
-        Properties usProperties;
-        Properties properties;
-        try {
-            usProperties = DuccFile.getUserSpecifiedProperties(eu, work);
-            properties = DuccFile.getProperties(eu, path);
-        } catch (Throwable e) {
-            throw new IOException(e);
-        }
-		processSpecificationData(request, response, usProperties, properties, null);
+		String mrNo = request.getParameter("id");
+		DuccWorkJob dwj = getManagedReservation(mrNo);
+		String resOwner = dwj.getStandardInfo().getUser();
+		EffectiveUser eu = EffectiveUser.create(request);
+		String reqUser = eu.get();
+		Map<String,Properties> map = null;
+		if(HandlersHelper.isResourceAuthorized(resOwner, reqUser)) {
+			map = helperSpecifications.getManagedReservationSpecificationProperties(dwj, eu);
+		}
+		if(map != null) {
+			Properties propertiesUser = map.get(PType.user.name());
+			Properties propertiesSystem = map.get(PType.all.name());
+			int usize = -1;
+			if(propertiesUser != null) {
+				usize = propertiesUser.size();
+			}
+			duccLogger.debug(methodName, jobid, "user="+usize);
+			int ssize = -1;
+			if(propertiesSystem != null) {
+				ssize = propertiesSystem.size();
+			}
+			duccLogger.debug(methodName, jobid, "system="+ssize);
+			processSpecificationData(request, response, propertiesUser, propertiesSystem, null);
+		}
+		else {
+			String msg = "(data not found)";
+            response.getWriter().println(msg);
+            duccLogger.warn(methodName, null, request.getParameter("id") + " failed: " + msg);
+		}
 		duccLogger.trace(methodName, null, messages.fetch("exit"));
 	}
 
@@ -2391,8 +2387,8 @@ public class DuccHandler extends DuccAbs
 		duccLogger.trace(methodName, null, messages.fetch("enter"));
 		StringBuffer sb = new StringBuffer();
 		try {
-			ServiceAuthorization sa = HandlersHelper.getServiceAuthorization(baseRequest);
-			switch(sa) {
+			DataAccessPermission dap = HandlersHelper.getServiceAuthorization(baseRequest);
+			switch(dap) {
 				case Read:
 				case Write:
 					String name = request.getParameter("name");
@@ -3568,8 +3564,8 @@ public class DuccHandler extends DuccAbs
 		String hint = getLoginRefreshHint(request, response);
 
 		String enable_or_disable = getDisabled();
-		ServiceAuthorization sa = HandlersHelper.getServiceAuthorization(baseRequest);
-		switch(sa) {
+		DataAccessPermission dap = HandlersHelper.getServiceAuthorization(baseRequest);
+		switch(dap) {
 			case Write:
 				enable_or_disable = getEnabledOrDisabled(request, response);
 				break;

Modified: uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandlerJsonFormat.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandlerJsonFormat.java?rev=1813881&r1=1813880&r2=1813881&view=diff
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandlerJsonFormat.java (original)
+++ uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandlerJsonFormat.java Tue Oct 31 13:12:38 2017
@@ -95,6 +95,7 @@ import org.apache.uima.ducc.ws.server.Js
 import org.apache.uima.ducc.ws.types.NodeId;
 import org.apache.uima.ducc.ws.types.UserId;
 import org.apache.uima.ducc.ws.utils.FormatHelper.Precision;
+import org.apache.uima.ducc.ws.utils.HandlersHelper;
 import org.apache.uima.ducc.ws.utils.alien.EffectiveUser;
 import org.apache.uima.ducc.ws.utils.alien.FileInfo;
 import org.eclipse.jetty.server.Request;
@@ -113,6 +114,9 @@ public class DuccHandlerJsonFormat exten
 	private static BrokerHelper brokerHelper = BrokerHelper.getInstance();
 	private static DatabaseHelper databaseHelper = DatabaseHelper.getInstance();
 	
+	private HelperSpecifications helperSpecifications = HelperSpecifications.getInstance();
+	private Gson gson = new Gson();
+	
 	private static JsonHelper jh = new JsonHelper();
 	
 	//private static PagingObserver pagingObserver = PagingObserver.getInstance();
@@ -128,6 +132,9 @@ public class DuccHandlerJsonFormat exten
 	
 	private final String jsonFormatJobProcessesData				= duccContextJsonFormat+"-job-processes";
 	
+	private final String jsonFormatJobSpecificationData					= duccContextJsonFormat+"-job-specification";
+	private final String jsonFormatManagedReservationSpecificationData	= duccContextJsonFormat+"-managed-reservation-specification";
+	
 	private final String jsonFormatMachines 		= duccContextJsonFormat+"-machines";
 	private final String jsonFormatReservations 	= duccContextJsonFormat+"-reservations";
 	
@@ -720,6 +727,114 @@ public class DuccHandlerJsonFormat exten
 		duccLogger.trace(methodName, jobid, messages.fetch("exit"));
 	}
 	
+	private void handleServletJsonFormatJobSpecificationData(String target,Request baseRequest,HttpServletRequest request,HttpServletResponse response) 
+	throws IOException, ServletException
+	{
+		String methodName = "handleServletJsonFormatJobSpecificationData";
+		duccLogger.trace(methodName, jobid, messages.fetch("enter"));
+		
+		String json = "{}";
+		
+		String jobNo = request.getParameter("id");
+		duccLogger.debug(methodName, jobid, "jobNo="+jobNo);
+		if(jobNo == null) {
+			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+		}
+		else {
+			DuccWorkJob dwj = Helper.getJob(jobNo);
+			duccLogger.debug(methodName, jobid, "dwj="+dwj);
+			if(dwj == null) {
+				response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+			}
+			else {
+				String resOwner = dwj.getStandardInfo().getUser();
+				duccLogger.debug(methodName, jobid, "resOwner="+resOwner);
+				if(resOwner == null) {
+					response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+				}
+				else {
+					EffectiveUser eu = EffectiveUser.create(request);
+					String reqUser = eu.get();
+					duccLogger.debug(methodName, jobid, "reqUser="+reqUser);
+					if(reqUser == null) {
+						response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
+					}
+					else {
+						if(HandlersHelper.isResourceAuthorized(resOwner, reqUser)) {
+							Map<String, Properties> properties = helperSpecifications.getJobSpecificationProperties(dwj, eu);
+							if(properties != null) {
+								if(!properties.isEmpty()) {
+									properties = helperSpecifications.convertAllToSystem(properties);
+									json = gson.toJson(properties);
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+		
+		duccLogger.debug(methodName, jobid, "json="+json);
+		response.getWriter().println(json);
+		response.setContentType("application/json");
+		
+		duccLogger.trace(methodName, jobid, messages.fetch("exit"));
+	}
+	
+	private void handleServletJsonFormatManagedReservationSpecificationData(String target,Request baseRequest,HttpServletRequest request,HttpServletResponse response) 
+	throws IOException, ServletException
+	{
+		String methodName = "handleServletJsonFormatManagedReservationSpecificationData";
+		duccLogger.trace(methodName, jobid, messages.fetch("enter"));
+				
+		String json = "{}";
+			
+		String resNo = request.getParameter("id");
+		duccLogger.debug(methodName, jobid, "resNo="+resNo);
+		if(resNo == null) {
+			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+		}
+		else {
+			DuccWorkJob mr = Helper.getManagedReservation(resNo);
+			duccLogger.debug(methodName, jobid, "mr="+mr);
+			if(mr == null) {
+				response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+			}
+			else {
+				String resOwner = mr.getStandardInfo().getUser();
+				duccLogger.debug(methodName, jobid, "resOwner="+resOwner);
+				if(resOwner == null) {
+					response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+				}
+				else {
+					EffectiveUser eu = EffectiveUser.create(request);
+					String reqUser = eu.get();
+					duccLogger.debug(methodName, jobid, "reqUser="+reqUser);
+					if(reqUser == null) {
+						response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
+					}
+					else {
+						if(HandlersHelper.isResourceAuthorized(resOwner, reqUser)) {
+							Map<String, Properties> properties = helperSpecifications.getManagedReservationSpecificationProperties(mr, eu);
+							if(properties != null) {
+								if(!properties.isEmpty()) {
+									properties = helperSpecifications.convertAllToSystem(properties);
+									json = gson.toJson(properties);
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+		
+		duccLogger.debug(methodName, jobid, "json="+json);
+		response.getWriter().println(json);
+		response.setContentType("application/json");
+				
+		duccLogger.trace(methodName, jobid, messages.fetch("exit"));
+	}
+	
 	private JsonArray buildReservationRow(HttpServletRequest request, IDuccWork duccwork, DuccData duccData, long now) {
 		JsonArray row = new JsonArray();
 		String reservationType = "Unmanaged";
@@ -2496,9 +2611,15 @@ public class DuccHandlerJsonFormat exten
 		else if(reqURI.startsWith(jsonFormatReservations)) {
 			handleServletJsonFormatReservations(target, baseRequest, request, response);
 		}
-		if(reqURI.startsWith(jsonFormatJobProcessesData)) {
+		else if(reqURI.startsWith(jsonFormatJobProcessesData)) {
 			handleServletJsonFormatJobProcessesData(target, baseRequest, request, response);
 		}
+		else if(reqURI.startsWith(jsonFormatJobSpecificationData)) {
+			handleServletJsonFormatJobSpecificationData(target, baseRequest, request, response);
+		}
+		else if(reqURI.startsWith(jsonFormatManagedReservationSpecificationData)) {
+			handleServletJsonFormatManagedReservationSpecificationData(target, baseRequest, request, response);
+		}
 		else {
 			handleServletUnknown(target, baseRequest, request, response);
 		}

Modified: uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/Helper.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/Helper.java?rev=1813881&r1=1813880&r2=1813881&view=diff
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/Helper.java (original)
+++ uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/Helper.java Tue Oct 31 13:12:38 2017
@@ -20,6 +20,7 @@ package org.apache.uima.ducc.ws.server;
 
 import java.text.DecimalFormat;
 import java.util.Date;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.TimeZone;
@@ -34,12 +35,15 @@ import org.apache.uima.ducc.common.utils
 import org.apache.uima.ducc.common.utils.SynchronizedSimpleDateFormat;
 import org.apache.uima.ducc.common.utils.id.DuccId;
 import org.apache.uima.ducc.transport.Constants;
+import org.apache.uima.ducc.transport.event.common.DuccWorkJob;
 import org.apache.uima.ducc.transport.event.common.IDuccProcess;
 import org.apache.uima.ducc.transport.event.common.IDuccProcessWorkItems;
 import org.apache.uima.ducc.transport.event.common.IDuccWorkJob;
+import org.apache.uima.ducc.transport.event.common.IDuccWorkMap;
 import org.apache.uima.ducc.transport.event.common.IProcessState.ProcessState;
 import org.apache.uima.ducc.transport.event.common.IResourceState.ProcessDeallocationType;
 import org.apache.uima.ducc.transport.event.common.TimeWindow;
+import org.apache.uima.ducc.ws.DuccData;
 import org.apache.uima.ducc.ws.DuccMachinesData;
 import org.apache.uima.ducc.ws.DuccMachinesDataHelper;
 import org.apache.uima.ducc.ws.MachineInfo;
@@ -62,6 +66,42 @@ public class Helper {
 	
 	public static String notAvailable = "N/A";
 	
+	public static DuccWorkJob getJob(String jobNo) {
+		DuccWorkJob job = null;
+		IDuccWorkMap duccWorkMap = DuccData.getInstance().get();
+		if(duccWorkMap.getJobKeySet().size()> 0) {
+			Iterator<DuccId> iterator = null;
+			iterator = duccWorkMap.getJobKeySet().iterator();
+			while(iterator.hasNext()) {
+				DuccId jobId = iterator.next();
+				String fid = ""+jobId.getFriendly();
+				if(jobNo.equals(fid)) {
+					job = (DuccWorkJob) duccWorkMap.findDuccWork(jobId);
+					break;
+				}
+			}
+		}
+		return job;
+	}
+	
+	public static DuccWorkJob getManagedReservation(String reservationNo) {
+		DuccWorkJob managedReservation = null;
+		IDuccWorkMap duccWorkMap = DuccData.getInstance().get();
+		if(duccWorkMap.getServiceKeySet().size()> 0) {
+			Iterator<DuccId> iterator = null;
+			iterator = duccWorkMap.getServiceKeySet().iterator();
+			while(iterator.hasNext()) {
+				DuccId jobId = iterator.next();
+				String fid = ""+jobId.getFriendly();
+				if(reservationNo.equals(fid)) {
+					managedReservation = (DuccWorkJob) duccWorkMap.findDuccWork(jobId);
+					break;
+				}
+			}
+		}
+		return managedReservation;
+	}
+	
 	public static String getDuration(DuccId jobId, String millisV2, String millisV1, Precision precision) {
 		String methodName = "getDuration";
 		String retVal = "";

Added: uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/HelperSpecifications.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/HelperSpecifications.java?rev=1813881&view=auto
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/HelperSpecifications.java (added)
+++ uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/HelperSpecifications.java Tue Oct 31 13:12:38 2017
@@ -0,0 +1,288 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.uima.ducc.ws.server;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.uima.ducc.cli.DuccUiConstants;
+import org.apache.uima.ducc.common.persistence.or.IDbDuccWorks;
+import org.apache.uima.ducc.common.persistence.or.ITypedProperties;
+import org.apache.uima.ducc.common.persistence.or.TypedProperties;
+import org.apache.uima.ducc.common.utils.DuccLogger;
+import org.apache.uima.ducc.common.utils.DuccLoggerComponents;
+import org.apache.uima.ducc.common.utils.id.DuccId;
+import org.apache.uima.ducc.database.DbDuccWorks;
+import org.apache.uima.ducc.transport.event.common.DuccWorkJob;
+import org.apache.uima.ducc.ws.utils.alien.EffectiveUser;
+
+public class HelperSpecifications {
+
+	/*
+	 * Specifications for Jobs, Managed Reservations are kept in DB as JSON data.
+	 * See DbDuccWorks.upsertSpecification for data format.
+	 * 
+	 * Legacy DUCC system (2.2.1 and prior) kept specification data in two properties files,
+	 * one for user specified and one for system (DUCC) specified.  The present code supports
+	 * both storage methodologies for backwards compatibility.
+	 */
+	
+	private static DuccLogger duccLogger = DuccLoggerComponents.getWsLogger(HelperSpecifications.class.getName());
+	private static DuccId jobid = null;
+
+	public static enum PType { user, all };
+
+	private static HelperSpecifications instance = new HelperSpecifications();
+	
+	public static HelperSpecifications getInstance() {
+		return instance;
+	}
+	
+	private IDbDuccWorks dbDuccWorks = null;
+
+	public HelperSpecifications() {
+		init();
+	}
+
+	private void init() {
+		String location = "init";
+		try {
+			dbDuccWorks = new DbDuccWorks(duccLogger);
+		} catch (Exception e) {
+			duccLogger.error(location, jobid, e);
+		}
+	}
+
+	/*
+	 * Fetch contents of two separate files, one each for user and system
+	 * properties
+	 * 
+	 * This method returns a map comprising two keyed entries, one for "user"
+	 * properties and one for "all" properties (ie user + system)
+	 */
+	private HashMap<String, Properties> getSpecificationPropertiesFromFiles(
+			DuccWorkJob dwj, EffectiveUser eu, String filename) {
+		String location = "getJobSpecificationPropertiesFromFiles";
+		DuccId duccid = jobid;
+		HashMap<String, Properties> map = new HashMap<String, Properties>();
+		try {
+			duccid = dwj.getDuccId();
+			if (dwj != null) {
+				String path = dwj.getUserLogDir() + filename;
+				String key;
+				Properties properties;
+				key = PType.user.name();
+				properties = DuccFile.getUserSpecifiedProperties(eu, dwj);
+				if (properties != null) {
+					if (properties.size() > 0) {
+						map.put(key, properties);
+					}
+				}
+				key = PType.all.name();
+				properties = DuccFile.getProperties(eu, path);
+				if (properties != null) {
+					if (properties.size() > 0) {
+						map.put(key, properties);
+					}
+				}
+			}
+		} catch (Throwable t) {
+			duccLogger.debug(location, duccid, t);
+			// oh well...
+		}
+		return map;
+	}
+
+	/*
+	 * DB comprises Map with two keyed entries, one for "user" properties and
+	 * the other for "system" properties.
+	 * 
+	 * This method returns a map comprising two keyed entries, one for "user"
+	 * properties and one for "all" properties (ie user + system)
+	 */
+	private Map<String, Properties> getSpecificationPropertiesFromDb(
+			String specificationType, Long id) {
+		String location = "getSpecificationPropertiesFromDb";
+		DuccId duccid = jobid;
+		Map<String, Properties> map = new HashMap<String, Properties>();
+		try {
+			ITypedProperties typedProperties = dbDuccWorks.fetchSpecification(
+					specificationType, id);
+			Map<String, Properties> dbmap = typedProperties.getMap();
+			if (dbmap != null) {
+				Properties user = dbmap.get(ITypedProperties.PropertyType.user
+						.name());
+				if (user != null) {
+					map.put(PType.user.name(), user);
+				}
+				Properties all = dbmap.get(ITypedProperties.PropertyType.system
+						.name());
+				if (all == null) {
+					all = new Properties();
+				}
+				all.putAll(user);
+				map.put(PType.all.name(), all);
+			}
+			duccid = new DuccId(id);
+			duccLogger.debug(location, duccid, "size=" + map.size());
+		} catch (Throwable t) {
+			duccLogger.debug(location, duccid, t);
+			// oh well...
+		}
+		return map;
+	}
+
+	private HashMap<String, Properties> getJobSpecificationPropertiesFromFiles(
+			DuccWorkJob dwj, EffectiveUser eu) {
+		String location = "getJobSpecificationPropertiesFromFiles";
+		DuccId duccid = jobid;
+		HashMap<String, Properties> map = new HashMap<String, Properties>();
+		try {
+			if (dwj != null) {
+				duccid = dwj.getDuccId();
+				String filename = DuccUiConstants.job_specification_properties;
+				map = getSpecificationPropertiesFromFiles(dwj, eu, filename);
+			}
+		} catch (Throwable t) {
+			duccLogger.debug(location, duccid, t);
+			// oh well...
+		}
+		return map;
+	}
+
+	private Map<String, Properties> getJobSpecificationPropertiesFromDb(
+			DuccWorkJob dwj, EffectiveUser eu) {
+		String location = "getJobSpecificationPropertiesFromDb";
+		DuccId duccid = jobid;
+		Map<String, Properties> map = new HashMap<String, Properties>();
+		try {
+			if (dwj != null) {
+				String specificationType = TypedProperties.SpecificationType.Job
+						.name();
+				Long id = dwj.getDuccId().getFriendly();
+				map = getSpecificationPropertiesFromDb(specificationType, id);
+			}
+		} catch (Throwable t) {
+			duccLogger.debug(location, duccid, t);
+			// oh well...
+		}
+		return map;
+	}
+	
+    public Map<String,Properties> getJobSpecificationProperties(DuccWorkJob dwj, EffectiveUser eu) {
+    	Map<String,Properties> map = new HashMap<String,Properties>();
+    	if(map.size() == 0) {
+    		map = getJobSpecificationPropertiesFromDb(dwj, eu);
+    	}
+    	if(map.size() == 0) {
+    		map = getJobSpecificationPropertiesFromFiles(dwj, eu);
+    	}
+    	if(map.size() == 0) {
+    		map = null;
+    	}
+    	return map;
+    }
+    
+    private Map<String,Properties> getManagedReservationSpecificationPropertiesFromDb(DuccWorkJob dwj, EffectiveUser eu) {
+    	String location = "getManagedReservationSpecificationPropertiesFromDb";
+    	DuccId duccid = jobid;
+    	Map<String,Properties> map = new HashMap<String,Properties>();
+    	try {
+    		if(dwj != null) {
+    			String specificationType = TypedProperties.SpecificationType.ManagedReservation.name();
+    			Long id = dwj.getDuccId().getFriendly();
+    			map = getSpecificationPropertiesFromDb(specificationType, id);
+    		}
+    	}
+    	catch (Throwable t) {
+    		duccLogger.debug(location, duccid, t);
+    		// oh well...
+    	}
+    	return map;
+    }
+    
+    private HashMap<String,Properties> getManagedReservationSpecificationPropertiesFromFiles(DuccWorkJob dwj, EffectiveUser eu) {
+    	String location = "getManagedReservationSpecificationPropertiesFromFiles";
+    	DuccId duccid = jobid;
+    	HashMap<String,Properties> map = new HashMap<String,Properties>();
+    	try {
+    		if(dwj != null) {
+    			duccid = dwj.getDuccId();
+    	        String filename =  DuccUiConstants.managed_reservation_properties;
+    	        map = getSpecificationPropertiesFromFiles(dwj, eu, filename);
+    		}
+    	}
+    	catch (Throwable t) {
+    		duccLogger.debug(location, duccid, t);
+    		// oh well...
+    	}
+    	return map;
+    }
+    
+    public Map<String,Properties> getManagedReservationSpecificationProperties(DuccWorkJob dwj, EffectiveUser eu) {
+    	Map<String,Properties> map = new HashMap<String,Properties>();
+    	if(map.size() == 0) {
+    		map = getManagedReservationSpecificationPropertiesFromDb(dwj, eu);
+    	}
+    	if(map.size() == 0) {
+    		map = getManagedReservationSpecificationPropertiesFromFiles(dwj, eu);
+    	}
+    	if(map.size() == 0) {
+    		map = null;
+    	}
+    	return map;
+    }
+    
+    //=====
+    
+    public Map<String,Properties> convertAllToSystem(Map<String,Properties> mapAll) {
+    	Map<String,Properties> mapSystem = null;
+    	if(mapAll != null) {
+    		mapSystem = new HashMap<String,Properties>();
+    		Properties propsU = mapAll.get("user");
+    		Properties propsA = mapAll.get("all");
+    		if(propsU == null) {
+    			if(propsA == null) {
+    				// nada
+    			}
+    			else {
+    				mapSystem.put("system", propsA);
+    			}
+    		}
+    		else {
+    			mapSystem.put("user", propsU);
+    			if(propsA == null) {
+    				// nada
+    			}
+    			else {
+    				Properties propsS = new Properties();
+    				for(Object key : propsA.keySet()) {
+    					if(!propsU.containsKey(key)) {
+    						propsS.put(key,propsA.get(key));
+    					}
+    				}
+    				mapSystem.put("system", propsS);
+    			}
+    		}
+    	}
+    	return mapSystem;
+    }
+	
+}

Propchange: uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/HelperSpecifications.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/HelperSpecifications.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/utils/HandlersHelper.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/utils/HandlersHelper.java?rev=1813881&r1=1813880&r2=1813881&view=diff
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/utils/HandlersHelper.java (original)
+++ uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/utils/HandlersHelper.java Tue Oct 31 13:12:38 2017
@@ -138,9 +138,9 @@ public class HandlersHelper {
 	}
 	
 	/**
-	 * Enumeration of possible Service Authorizations
+	 * Enumeration of possible data access permissions
 	 */
-	public enum ServiceAuthorization { None, Read, Write };
+	public enum DataAccessPermission { None, Read, Write };
 	
 	/**
 	 * Transform service number into DuccId
@@ -302,13 +302,13 @@ public class HandlersHelper {
 	/**
 	 * Determine service authorization level for request
 	 */
-	public static ServiceAuthorization getServiceAuthorization(Request request) {
+	public static DataAccessPermission getServiceAuthorization(Request request) {
 		String methodName = "getServiceAuthorization";
 		duccLogger.trace(methodName, jobid, messages.fetch("enter"));
-		ServiceAuthorization retVal = ServiceAuthorization.None;
+		DataAccessPermission retVal = DataAccessPermission.None;
 		try {
 			if(request == null) {
-				// request not specified ==> ServiceAuthorization.None
+				// request not specified ==> DataAccessPermissions.None
 			}
 			else {
 				String reqUser = duccWebSessionManager.getUserId(request);
@@ -316,29 +316,29 @@ public class HandlersHelper {
 				ServicesRegistry servicesRegistry = ServicesRegistry.getInstance();
 				ServicesRegistryMapPayload payload = servicesRegistry.findService(name);
 				if(payload == null) {
-					// service not found ==> ServiceAuthorization.None
+					// service not found ==> DataAccessPermissions.None
 				}
 				else {
 					Properties svc = payload.svc;
 					Properties meta = payload.meta;
 					// write access for service owner
 					if(isServiceOwner(reqUser, meta)) {
-						retVal = ServiceAuthorization.Write;
+						retVal = DataAccessPermission.Write;
 					}
 					// write access for service administrator
 					else if(isServiceAdministrator(reqUser, svc)) {
-						retVal = ServiceAuthorization.Write;
+						retVal = DataAccessPermission.Write;
 					}
 					// Don't permit write access for ducc administrator
 					//else if(isDuccAdministrator(reqUser, meta)) {
-					//	retVal = ServiceAuthorization.Write;
+					//	retVal = DataAccessPermissions.Write;
 					//}
 					// read access only if user can read db.access file
 					else if(isServiceFileAccessForRead(reqUser, meta)) {
-						retVal = ServiceAuthorization.Read;
+						retVal = DataAccessPermission.Read;
 					}
 					else {
-						// none of the above ==> ServiceAuthorization.None
+						// none of the above ==> DataAccessPermissions.None
 					}
 				}
 			}
@@ -349,4 +349,54 @@ public class HandlersHelper {
 		duccLogger.trace(methodName, jobid, messages.fetch("exit"));
 		return retVal;
 	}
+	
+	/**
+	 * Determine resource authorization level, given resource owner and resource access requester
+	 */
+	public static DataAccessPermission getResourceAuthorization(String resOwner, String reqUser) {
+		String methodName = "getServiceAuthorization";
+		duccLogger.trace(methodName, jobid, messages.fetch("enter"));
+		DataAccessPermission retVal = DataAccessPermission.None;
+		try {
+			if(resOwner == reqUser) {
+				retVal = DataAccessPermission.Read;
+			}
+			else {
+				String home = getSecurityHome(resOwner.trim());
+				if(home != null) {
+					if(!home.endsWith(File.separator)) {
+						home = home+File.separator;
+					}
+					String path = home+".ducc"+File.separator+"db.access";
+					boolean readable = isFileReadable(reqUser, path);
+					if(readable) {
+						retVal = DataAccessPermission.Read;
+						duccLogger.debug(methodName, jobid, "owner="+resOwner+" "+"user="+reqUser+" "+retVal);
+					}
+				}
+			}
+		}
+		catch(Exception e) {
+			duccLogger.error(methodName, jobid, e);
+		}
+		duccLogger.trace(methodName, jobid, messages.fetch("exit"));
+		return retVal;
+	}
+	
+	/**
+	 * Determine resource accessibility, given resource owner and resource access requester
+	 */
+	public static boolean isResourceAuthorized(String resOwner, String reqUser) {
+		boolean retVal = false;
+		DataAccessPermission dap = getResourceAuthorization(resOwner, reqUser);
+		switch(dap) {
+			case Read:
+			case Write:
+				retVal = true;
+				break;
+			default:
+				break;
+		}
+		return retVal;
+	}
 }