You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@river.apache.org by gt...@apache.org on 2014/01/13 04:35:32 UTC
[25/40] git commit: Added property setting to components called out
in config.xml Completed monitoring of deployment directory - services now
auto-deploy while container is live.
Added property setting to components called out in config.xml
Completed monitoring of deployment directory - services now auto-deploy while container is live.
Project: http://git-wip-us.apache.org/repos/asf/river-container/repo
Commit: http://git-wip-us.apache.org/repos/asf/river-container/commit/60c5c7fe
Tree: http://git-wip-us.apache.org/repos/asf/river-container/tree/60c5c7fe
Diff: http://git-wip-us.apache.org/repos/asf/river-container/diff/60c5c7fe
Branch: refs/heads/master
Commit: 60c5c7fe71d7a61b7f4d97688914cb708bef24f5
Parents: 42f2ef2
Author: Greg Trasuk <tr...@trasuk.com>
Authored: Thu Nov 28 02:37:51 2013 -0500
Committer: Greg Trasuk <tr...@trasuk.com>
Committed: Thu Nov 28 02:37:51 2013 -0500
----------------------------------------------------------------------
product/src/main/root/bin/logging.properties | 3 +-
.../src/main/root/profile/client/client-app.cfg | 95 +++++++++
product/src/main/root/profile/client/config.xml | 4 +-
.../root/profile/client/service-starter.cfg | 95 ---------
.../src/main/root/profile/default/config.xml | 3 +-
.../root/profile/default/service-starter.cfg | 2 +-
.../org/apache/river/container/Bootstrap.java | 103 ++++++---
.../apache/river/container/MessageNames.java | 11 +-
.../deployer/StarterServiceDeployer.java | 51 +++--
.../deployer/StarterServiceLifeCycleSM.java | 1 +
.../container/deployer/StartupDeployer.java | 211 +++++++++++++++----
.../apache/river/container/Messages.properties | 9 +
12 files changed, 401 insertions(+), 187 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/river-container/blob/60c5c7fe/product/src/main/root/bin/logging.properties
----------------------------------------------------------------------
diff --git a/product/src/main/root/bin/logging.properties b/product/src/main/root/bin/logging.properties
index 62fab38..aebd1a5 100644
--- a/product/src/main/root/bin/logging.properties
+++ b/product/src/main/root/bin/logging.properties
@@ -50,7 +50,7 @@ java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
# Provides extra control for each logger.
############################################################
-org.apache.river.container.level = FINER
+org.apache.river.container.level = FINE
org.apache.river.container.ShowContextToConsole.level=INFO
@@ -58,4 +58,5 @@ net.jini.config.level=INFO
org.apache.river.container.security.ContainerCodePolicy.level=INFO
org.apache.river.container.deployer.ClasspathFilterBuilder.level=INFO
org.apache.river.container.deployer.DeployerConfigParser=INFO
+org.apache.river.container.hsm.level=SEVERE
net.jini.config.level=INFO
http://git-wip-us.apache.org/repos/asf/river-container/blob/60c5c7fe/product/src/main/root/profile/client/client-app.cfg
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/client/client-app.cfg b/product/src/main/root/profile/client/client-app.cfg
new file mode 100644
index 0000000..d62e2cc
--- /dev/null
+++ b/product/src/main/root/profile/client/client-app.cfg
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+// Sample file that our policy file parser should be able to process.
+
+// Grants given to all applications.
+grant {
+ //java.security.AllPermission;
+ //java.io.FilePermission "${serviceArchive}" "read";
+ java.io.FilePermission "-" "read";
+ java.net.SocketPermission "*" "connect,listen,accept,resolve";
+
+ // Required for VFSFileManager
+ java.util.PropertyPermission "java.io.tmpdir" "read";
+ java.util.PropertyPermission "os.*" "read";
+ java.util.PropertyPermission "path.*" "read";
+ java.lang.RuntimePermission "getClassLoader";
+ java.lang.RuntimePermission "setContextClassLoader";
+ /* net.jini.security.Security requires createSecurityManager, but we
+ don't grant 'setSecurityManager'. */
+ java.lang.RuntimePermission "createSecurityManager";
+ java.lang.RuntimePermission "getProtectionDomain";
+ java.lang.RuntimePermission "setFactory";
+ java.lang.RuntimePermission "modifyThread";
+ java.lang.RuntimePermission "modifyThreadGroup";
+ java.security.SecurityPermission "getDomainCombiner";
+ java.security.SecurityPermission "createAccessControlContext";
+ java.security.SecurityPermission "getPolicy";
+
+ // BasicProxyPreparer requirements:
+ javax.security.auth.AuthPermission "getSubject";
+ // Should not be required once UmbrellaGrantPolicy is implemented.
+ // TODO: Config file parser doesn't recognize \"
+ net.jini.security.GrantPermission "delim=| java.lang.RuntimePermission |accessClassInPackage.com.sun.proxy|";
+
+ net.jini.security.policy.UmbrellaGrantPermission;
+ com.sun.jini.thread.ThreadPoolPermission "getSystemThreadPool";
+ com.sun.jini.thread.ThreadPoolPermission "getUserThreadPool";
+ com.sun.jini.discovery.internal.EndpointInternalsPermission "set";
+ com.sun.jini.discovery.internal.EndpointInternalsPermission "get";
+ java.lang.reflect.ReflectPermission "suppressAccessChecks";
+ net.jini.export.ExportPermission "exportRemoteInterface.*";
+ net.jini.discovery.DiscoveryPermission "*";
+ java.lang.RuntimePermission "shutdownHooks";
+ java.util.PropertyPermission "*" "read";
+
+ java.lang.RuntimePermission "accessClassInPackage.com.sun.proxy";
+
+ // Only in client configuration - apps can call System.exit()
+ java.lang.RuntimePermission "exitVM.*";
+}
+
+classloader {
+ // Variables required to set up the application classloader.
+ //For a privileged application deployer, parent=containerClassLoader;
+ parent systemClassLoader;
+
+ jars {
+ commons-vfs2-2.0.jar,
+ commons-logging-1.1.1.jar,
+ jsk-platform-${jsk-version}.jar,
+ jsk-lib-${jsk-version}.jar,
+ jsk-resources-${jsk-version}.jar,
+ river-container-core-1.0-SNAPSHOT.jar(org.apache.river.container.liaison.Strings,
+ org.apache.river.container.liaison.VirtualFileSystemConfiguration,
+ org.apache.river.container.liaison.VirtualFileSystemConfiguration$MyConfigurationFile,
+ "META-INF/services/*")
+ }
+
+ codebase {jsk-dl-${jsk-version}.jar}
+}
+
+configuration {
+ // Anything on the left-hand side of '=' is set into the application config
+ // as a "special variable, accessible through '$name'.
+ discoveryGroup=defaultDiscoveryGroup;
+
+ // For privileged deployer, include
+ // context=context;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/river-container/blob/60c5c7fe/product/src/main/root/profile/client/config.xml
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/client/config.xml b/product/src/main/root/profile/client/config.xml
index 1c108d1..9b01480 100644
--- a/product/src/main/root/profile/client/config.xml
+++ b/product/src/main/root/profile/client/config.xml
@@ -39,13 +39,11 @@
<!-- Deployer for 'service-starter'-style applications. -->
<cfg:component class="org.apache.river.container.deployer.StarterServiceDeployer">
- <cfg:property name="config" value="service-starter.cfg"/>
- <cfg:property name="deployDirectory" value="deploy"/>
+ <cfg:property name="config" value="client-app.cfg"/>
</cfg:component>
<!-- Deployer for 'service-starter'-style applications. -->
<cfg:component class="org.apache.river.container.deployer.ClientAppDeployer">
- <cfg:property name="config" value="client-app.cfg"/>
<cfg:property name="deployDirectory" value="deploy"/>
</cfg:component>
http://git-wip-us.apache.org/repos/asf/river-container/blob/60c5c7fe/product/src/main/root/profile/client/service-starter.cfg
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/client/service-starter.cfg b/product/src/main/root/profile/client/service-starter.cfg
deleted file mode 100644
index d62e2cc..0000000
--- a/product/src/main/root/profile/client/service-starter.cfg
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.
- */
-
-// Sample file that our policy file parser should be able to process.
-
-// Grants given to all applications.
-grant {
- //java.security.AllPermission;
- //java.io.FilePermission "${serviceArchive}" "read";
- java.io.FilePermission "-" "read";
- java.net.SocketPermission "*" "connect,listen,accept,resolve";
-
- // Required for VFSFileManager
- java.util.PropertyPermission "java.io.tmpdir" "read";
- java.util.PropertyPermission "os.*" "read";
- java.util.PropertyPermission "path.*" "read";
- java.lang.RuntimePermission "getClassLoader";
- java.lang.RuntimePermission "setContextClassLoader";
- /* net.jini.security.Security requires createSecurityManager, but we
- don't grant 'setSecurityManager'. */
- java.lang.RuntimePermission "createSecurityManager";
- java.lang.RuntimePermission "getProtectionDomain";
- java.lang.RuntimePermission "setFactory";
- java.lang.RuntimePermission "modifyThread";
- java.lang.RuntimePermission "modifyThreadGroup";
- java.security.SecurityPermission "getDomainCombiner";
- java.security.SecurityPermission "createAccessControlContext";
- java.security.SecurityPermission "getPolicy";
-
- // BasicProxyPreparer requirements:
- javax.security.auth.AuthPermission "getSubject";
- // Should not be required once UmbrellaGrantPolicy is implemented.
- // TODO: Config file parser doesn't recognize \"
- net.jini.security.GrantPermission "delim=| java.lang.RuntimePermission |accessClassInPackage.com.sun.proxy|";
-
- net.jini.security.policy.UmbrellaGrantPermission;
- com.sun.jini.thread.ThreadPoolPermission "getSystemThreadPool";
- com.sun.jini.thread.ThreadPoolPermission "getUserThreadPool";
- com.sun.jini.discovery.internal.EndpointInternalsPermission "set";
- com.sun.jini.discovery.internal.EndpointInternalsPermission "get";
- java.lang.reflect.ReflectPermission "suppressAccessChecks";
- net.jini.export.ExportPermission "exportRemoteInterface.*";
- net.jini.discovery.DiscoveryPermission "*";
- java.lang.RuntimePermission "shutdownHooks";
- java.util.PropertyPermission "*" "read";
-
- java.lang.RuntimePermission "accessClassInPackage.com.sun.proxy";
-
- // Only in client configuration - apps can call System.exit()
- java.lang.RuntimePermission "exitVM.*";
-}
-
-classloader {
- // Variables required to set up the application classloader.
- //For a privileged application deployer, parent=containerClassLoader;
- parent systemClassLoader;
-
- jars {
- commons-vfs2-2.0.jar,
- commons-logging-1.1.1.jar,
- jsk-platform-${jsk-version}.jar,
- jsk-lib-${jsk-version}.jar,
- jsk-resources-${jsk-version}.jar,
- river-container-core-1.0-SNAPSHOT.jar(org.apache.river.container.liaison.Strings,
- org.apache.river.container.liaison.VirtualFileSystemConfiguration,
- org.apache.river.container.liaison.VirtualFileSystemConfiguration$MyConfigurationFile,
- "META-INF/services/*")
- }
-
- codebase {jsk-dl-${jsk-version}.jar}
-}
-
-configuration {
- // Anything on the left-hand side of '=' is set into the application config
- // as a "special variable, accessible through '$name'.
- discoveryGroup=defaultDiscoveryGroup;
-
- // For privileged deployer, include
- // context=context;
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/river-container/blob/60c5c7fe/product/src/main/root/profile/default/config.xml
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/default/config.xml b/product/src/main/root/profile/default/config.xml
index 06108ed..7d81f52 100644
--- a/product/src/main/root/profile/default/config.xml
+++ b/product/src/main/root/profile/default/config.xml
@@ -40,14 +40,13 @@
<!-- Deployer for 'service-starter'-style applications. -->
<cfg:component class="org.apache.river.container.deployer.StarterServiceDeployer">
<cfg:property name="config" value="service-starter.cfg"/>
- <cfg:property name="deployDirectory" value="deploy"/>
</cfg:component>
<!-- Deployer for applications that are in the 'deploy' directory
at startup. -->
<cfg:component class="org.apache.river.container.deployer.StartupDeployer">
- <cfg:property name="config" value="service-starter.cfg"/>
<cfg:property name="deployDirectory" value="deploy"/>
+ <cfg:property name="autoDeploy" value="true"/>
</cfg:component>
<!-- Deployer for 'system apps' like the remote deployment service
http://git-wip-us.apache.org/repos/asf/river-container/blob/60c5c7fe/product/src/main/root/profile/default/service-starter.cfg
----------------------------------------------------------------------
diff --git a/product/src/main/root/profile/default/service-starter.cfg b/product/src/main/root/profile/default/service-starter.cfg
index d62e2cc..4b2a5a0 100644
--- a/product/src/main/root/profile/default/service-starter.cfg
+++ b/product/src/main/root/profile/default/service-starter.cfg
@@ -46,7 +46,7 @@ grant {
javax.security.auth.AuthPermission "getSubject";
// Should not be required once UmbrellaGrantPolicy is implemented.
// TODO: Config file parser doesn't recognize \"
- net.jini.security.GrantPermission "delim=| java.lang.RuntimePermission |accessClassInPackage.com.sun.proxy|";
+ // net.jini.security.GrantPermission "delim=| java.lang.RuntimePermission |accessClassInPackage.com.sun.proxy|";
net.jini.security.policy.UmbrellaGrantPermission;
com.sun.jini.thread.ThreadPoolPermission "getSystemThreadPool";
http://git-wip-us.apache.org/repos/asf/river-container/blob/60c5c7fe/river-container-core/src/main/java/org/apache/river/container/Bootstrap.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/Bootstrap.java b/river-container-core/src/main/java/org/apache/river/container/Bootstrap.java
index d5a2fed..0943d4c 100644
--- a/river-container-core/src/main/java/org/apache/river/container/Bootstrap.java
+++ b/river-container-core/src/main/java/org/apache/river/container/Bootstrap.java
@@ -17,6 +17,10 @@
*/
package org.apache.river.container;
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
@@ -39,22 +43,23 @@ import org.apache.river.container.config.*;
import org.xml.sax.SAXException;
/**
- Bootstrap loader for the container. Performs roughly the following: <ul>
- <li>Based on the configuration parameter fed in at the command line, determine
- the configuration directory and the config file.</li> <li>Read the
- configuration file</li> <li>Based on the classpath declared in the config file,
- create the container's classloader.</li> <li>Using that classloader, create the
- context.</li> <li>Load any command-line parameters into the context</li>
- <li>Create all the elements (beans, discovery sets, etc) that are called out in
- the config file and put them into the context. This will cause those beans to
- setup and initialize themselves.</li> </li>
-
- @author trasukg
+ * Bootstrap loader for the container. Performs roughly the following: <ul>
+ * <li>Based on the configuration parameter fed in at the command line,
+ * determine the configuration directory and the config file.</li> <li>Read the
+ * configuration file</li> <li>Based on the classpath declared in the config
+ * file, create the container's classloader.</li> <li>Using that classloader,
+ * create the context.</li> <li>Load any command-line parameters into the
+ * context</li>
+ * <li>Create all the elements (beans, discovery sets, etc) that are called out
+ * in the config file and put them into the context. This will cause those beans
+ * to setup and initialize themselves.</li> </li>
+ *
+ * @author trasukg
*/
public class Bootstrap {
- private static final Logger log =
- Logger.getLogger(Bootstrap.class.getName(), MessageNames.BUNDLE_NAME);
+ private static final Logger log
+ = Logger.getLogger(Bootstrap.class.getName(), MessageNames.BUNDLE_NAME);
public static void main(String args[]) {
try {
@@ -117,37 +122,37 @@ public class Bootstrap {
List<String> seen,
Map<String, Classpath> classpaths,
String id) throws MalformedURLException {
- if (classLoaders.containsKey(id ) ){
+ if (classLoaders.containsKey(id)) {
return classLoaders.get(id);
}
if (seen.contains(id)) {
- throw new ConfigurationException(MessageNames.CIRCULAR_CLASSPATH, id);
+ throw new ConfigurationException(MessageNames.CIRCULAR_CLASSPATH, id);
}
// Add the id to the list of classloaders we have attempted to build.
seen.add(id);
- Classpath classpath=classpaths.get(id);
- if (classpath==null) {
+ Classpath classpath = classpaths.get(id);
+ if (classpath == null) {
throw new ConfigurationException(MessageNames.CLASSPATH_UNDEFINED, id);
}
- String parentClasspathId=classpath.getParent();
- ClassLoader parentClassLoader=null;
- if (parentClasspathId!=null && !Strings.EMPTY.equals(parentClasspathId) ){
- parentClassLoader=resolveClassLoader(classLoaders, seen, classpaths, parentClasspathId);
+ String parentClasspathId = classpath.getParent();
+ ClassLoader parentClassLoader = null;
+ if (parentClasspathId != null && !Strings.EMPTY.equals(parentClasspathId)) {
+ parentClassLoader = resolveClassLoader(classLoaders, seen, classpaths, parentClasspathId);
} else {
/* Should be the 'extension' classloader. */
- parentClassLoader=Bootstrap.class.getClassLoader().getParent();
+ parentClassLoader = Bootstrap.class.getClassLoader().getParent();
}
URL[] classpathUrls;
classpathUrls = findClasspathURLS(classpath.getValue());
-
+
SettableCodebaseClassLoader classLoader = new SettableCodebaseClassLoader(classpathUrls,
parentClassLoader);
classLoaders.put(id, classLoader);
log.log(Level.FINE, MessageNames.CONFIGURED_CLASSPATH, new Object[]{
- id,
- Utils.format(classpathUrls)});
+ id,
+ Utils.format(classpathUrls)});
seen.remove(id);
- return classLoader;
+ return classLoader;
}
static void initializeContainer(String args[]) throws SAXException, JAXBException, FileNotFoundException, MalformedURLException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException, ConfigurationException, Exception {
@@ -228,6 +233,16 @@ public class Bootstrap {
Class compClass = Class.forName(c.getClazz(), true, classLoader);
String name = c.getName();
Object instance = compClass.newInstance();
+ for (Property p : c.getProperty()) {
+ setPropertyOnComponent(instance, p.getName(), p.getValue());
+ log.log(Level.FINER, MessageNames.SET_PROPERTY_ON_COMPONENT,
+ new Object[] {
+ p.getName(),
+ c.getClazz(),
+ c.getName(),
+ p.getValue()
+ });
+ }
if (name == null || name.trim().length() == 0) {
putMethod.invoke(context, instance);
} else {
@@ -250,6 +265,42 @@ public class Bootstrap {
throw new ConfigurationException(MessageNames.UNSUPPORTED_ELEMENT, element.getClass().getName());
}
}
+
+ private static void setPropertyOnComponent(Object instance, String propertyName, String propertyValue) {
+ try {
+ BeanInfo info = Introspector.getBeanInfo(instance.getClass());
+ PropertyDescriptor pd=findPropertyDescriptor(info, propertyName);
+ Object convertedValue=convert(propertyValue, pd.getPropertyType());
+ pd.getWriteMethod().invoke(instance, convertedValue);
+ } catch (Throwable t) {
+ throw new ConfigurationException(t, MessageNames.FAILED_TO_SET_PROPERTY, propertyName, instance.getClass(), propertyValue);
+ }
+ }
+
+ private static PropertyDescriptor findPropertyDescriptor(BeanInfo info, String propertyName) throws IntrospectionException {
+ for (PropertyDescriptor possible: info.getPropertyDescriptors()) {
+ if (propertyName.equals(possible.getName())) {
+ return possible;
+ }
+ }
+ throw new IntrospectionException(propertyName);
+ }
+
+ private static Object convert(String value, Class targetType) {
+ if (targetType.equals(Boolean.class) || targetType.equals(boolean.class)) {
+ return Boolean.parseBoolean(value);
+ } else if (targetType.equals(String.class)) {
+ return value;
+ } else if (targetType.equals(Integer.class) || targetType.equals(int.class)) {
+ return Integer.parseInt(value);
+ } else if (targetType.equals(Double.class) || targetType.equals(double.class)) {
+ return Double.parseDouble(value);
+ } else if (targetType.equals(Float.class) || targetType.equals(float.class)) {
+ return Float.parseFloat(value);
+ }
+ throw new UnsupportedOperationException();
+ }
+
/*
static URL[] findClasspathURLS(ContainerConfig containerConfig) throws
MalformedURLException { String classpathStr =
http://git-wip-us.apache.org/repos/asf/river-container/blob/60c5c7fe/river-container-core/src/main/java/org/apache/river/container/MessageNames.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/MessageNames.java b/river-container-core/src/main/java/org/apache/river/container/MessageNames.java
index 2ffa0d5..a566d03 100644
--- a/river-container-core/src/main/java/org/apache/river/container/MessageNames.java
+++ b/river-container-core/src/main/java/org/apache/river/container/MessageNames.java
@@ -44,6 +44,8 @@ public class MessageNames {
ADDED_PLATFORM_CODEBASE_JAR="addedPlatformCodebaseJar",
ADDING_CLASSPATH_ENTRY="addingClasspathEntry",
ANNOTATED_OBJECT_DEPLOYER_HAS_UNRESOLVED_DEPENDENCIES="annotatedObjectDeployerHasUnresolvedDependencies",
+ AUTO_DEPLOYER_FAILED_INIT="autoDeployerFailedInit",
+ AUTO_DEPLOYER_STARTING="autoDeployerStarting",
BAD_CLASSPATH_EXPR="badClasspathExpression",
BAD_MEMBER_FOR_INJECTED_ANNOTATION="badMemberForInjectedAnnotation",
BAD_MEMBER_FOR_NAME_ANNOTATION="badMemberForNameAnnotation",
@@ -79,6 +81,8 @@ public class MessageNames {
FAILED_CLEAN_SHUTDOWN="failedCleanShutdown",
FAILED_DEPLOY_SERVICE="failedDeployService",
FAILED_READ_PROPERTIES="failedReadProperties",
+ FAILED_TO_REMOVE_MBEAN="failedToRemoveMBean",
+ FAILED_TO_SET_PROPERTY="failedToSetProperty",
FOUND_NO_SERVICE_ARCHIVES="foundNoServiceArchives",
FOUND_SERVICE_ARCHIVES="foundServiceArchives",
ILLEGAL_ARGUMENT_EXCEPTION="illegalArgumentException",
@@ -108,10 +112,12 @@ public class MessageNames {
READING_OBJECT_NON_ANNOTATED_MEMBER_FOUND="readingObject.nonAnnotatedMemberFound",
RECEIVED_START="receivedStart",
RECEIVED_START_WITH_ARGS="receivedStartWithArgs",
+ SCANNING_DEPLOYMENT_DIRECTORY="scanningDeploymentDirectory",
SECURITY_INIT_FAILED="securityInitializationFailed",
SECURITY_INIT_SUCCEEDED="securityInitializationSucceeded",
SECURITY_INIT_WRONG_POLICY="securityInitializationWrongPolicy",
SERVICE_PARENT_CLASSLOADER_IS="serviceParentClassloaderIs",
+ SET_PROPERTY_ON_COMPONENT="setPropertyOnComponent",
SHOW_COMMAND_LINE_ARGUMENTS="showCommandLineArguments",
SHUTDOWN_FAILED="shutdownFailed",
SHUTDOWN_METHOD_HAS_PARAMETERS="shutdownMethodHasParameters",
@@ -119,10 +125,13 @@ public class MessageNames {
STARTER_SERVICE_DEPLOYER_FAILED_INIT="starterServiceDeployerFailedInit",
STARTER_SERVICE_DEPLOYER_INITIALIZED="starterServiceDeployerInitialized",
STARTER_SERVICE_DEPLOYER_STARTING="starterServiceDeployerStarting",
+ STARTING_SERVICE="startingService",
STARTUP_DEPLOYER_FAILED_INIT="startupDeployerFailedInit",
STARTUP_DEPLOYER_INITIALIZED="startupDeployerInitialized",
STARTUP_DEPLOYER_STARTING="startupDeployerStarting",
+ STOPPING_SERVICE="stoppingService",
SYSTEM_CLASSLOADER_IS="systemClassLoaderIs",
UNRESOLVED_DEPENDENCY="unresolvedDependency",
- UNSUPPORTED_ELEMENT="unsupportedElement";
+ UNSUPPORTED_ELEMENT="unsupportedElement",
+ UPDATING_SERVICE="updatingService";
}
http://git-wip-us.apache.org/repos/asf/river-container/blob/60c5c7fe/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java b/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java
index d98ddd1..61766e1 100644
--- a/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java
+++ b/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceDeployer.java
@@ -31,14 +31,20 @@ import java.lang.reflect.Method;
import java.net.URL;
import java.security.CodeSource;
import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
import java.security.Principal;
import java.security.cert.Certificate;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
+import net.jini.security.GrantPermission;
import net.jini.security.policy.DynamicPolicyProvider;
+import net.jini.security.policy.UmbrellaGrantPermission;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileType;
@@ -69,8 +75,8 @@ import org.apache.river.container.work.WorkManager;
*/
public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
- private static final Logger log =
- Logger.getLogger(StarterServiceDeployer.class.getName(), MessageNames.BUNDLE_NAME);
+ private static final Logger log
+ = Logger.getLogger(StarterServiceDeployer.class.getName(), MessageNames.BUNDLE_NAME);
@Injected(style = InjectionStyle.BY_TYPE)
private FileUtility fileUtility = null;
@Injected(style = InjectionStyle.BY_TYPE)
@@ -132,8 +138,8 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
new Class[]{ASTconfig.class, ASTclassloader.class, ASTparent.class}).get(0).jjtGetChild(0).toString();
log.log(Level.FINE, MessageNames.SERVICE_PARENT_CLASSLOADER_IS, parentLoaderName);
ClassLoader parentLoader = (ClassLoader) context.get(parentLoaderName);
- VirtualFileSystemClassLoader cl =
- createChildOfGivenClassloader(parentLoader, codeSource);
+ VirtualFileSystemClassLoader cl
+ = createChildOfGivenClassloader(parentLoader, codeSource);
/*
Include platform jars from the container's lib directory.
*/
@@ -169,8 +175,8 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
/*
Create the service classloader.
*/
- VirtualFileSystemClassLoader cl =
- new VirtualFileSystemClassLoader(null, parent, codeSource);
+ VirtualFileSystemClassLoader cl
+ = new VirtualFileSystemClassLoader(null, parent, codeSource);
return cl;
}
@@ -232,7 +238,7 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
throw new LocalizedRuntimeException(MessageNames.BUNDLE_NAME,
MessageNames.CANT_READ_START_PROPERTIES,
new Object[]{Strings.START_PROPERTIES,
- serviceRoot.getName().getBaseName()});
+ serviceRoot.getName().getBaseName()});
}
Properties startProps = propertiesFileReader.getProperties(startProperties);
return startProps;
@@ -252,6 +258,7 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
workingDir = new File(serviceRoot.getURL().toURI());
}
+
grantPermissions(cl,
new Permission[]{new FilePermission(workingDir.getAbsolutePath(), Strings.READ)});
Utils.logClassLoaderHierarchy(log, Level.FINE, this.getClass());
@@ -328,9 +335,9 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
void prepareService(ApplicationEnvironment env) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
- CodeSource serviceCodeSource =
- new CodeSource(findServiceURL(env.getServiceArchive(), env.getServiceRoot()),
- new Certificate[0]);
+ CodeSource serviceCodeSource
+ = new CodeSource(findServiceURL(env.getServiceArchive(), env.getServiceRoot()),
+ new Certificate[0]);
log.log(Level.INFO, MessageNames.CODESOURCE_IS,
new Object[]{env.getServiceName(), serviceCodeSource});
VirtualFileSystemClassLoader cl = createServiceClassloader(env.getServiceRoot(), serviceCodeSource);
@@ -339,8 +346,8 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
/*
Create a codebase context.
*/
- CodebaseContext codebaseContext =
- codebaseHandler.createContext(env.getServiceName());
+ CodebaseContext codebaseContext
+ = codebaseHandler.createContext(env.getServiceName());
env.setCodebaseContext(codebaseContext);
addPlatformCodebaseJars(codebaseContext);
exportServiceCodebaseJars(env.getServiceRoot(), codebaseContext);
@@ -421,6 +428,7 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
private void grantPermissions(ClassLoader cl, Permission[] perms) {
try {
+ perms=expandUmbrella(perms);
Class clazz = Class.forName(VirtualFileSystemConfiguration.class.getName(), true, cl);
securityPolicy.grant(clazz, new Principal[0], perms);
@@ -429,6 +437,25 @@ public class StarterServiceDeployer implements StarterServiceDeployerMXBean {
}
}
+ private static Permission[] expandUmbrella(Permission[] perms) {
+ PermissionCollection pc=new Permissions();
+
+ for (Permission p: perms) {
+ pc.add(p);
+ }
+ if (pc.implies(new UmbrellaGrantPermission())) {
+ List l = Collections.list(pc.elements());
+ pc.add(new GrantPermission(
+ (Permission[]) l.toArray(new Permission[l.size()])));
+ }
+ List<Permission> permList=new ArrayList<Permission>();
+
+ for (Enumeration<Permission> en=pc.elements(); en.hasMoreElements();) {
+ permList.add(en.nextElement());
+ }
+ return permList.toArray(new Permission[0]);
+ }
+
private Object instantiateService(ClassLoader cl, String className, String[] parms)
throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, InstantiationException {
Class clazz = Class.forName(className, true, cl);
http://git-wip-us.apache.org/repos/asf/river-container/blob/60c5c7fe/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceLifeCycleSM.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceLifeCycleSM.java b/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceLifeCycleSM.java
index 355074a..012b8ee 100644
--- a/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceLifeCycleSM.java
+++ b/river-container-core/src/main/java/org/apache/river/container/deployer/StarterServiceLifeCycleSM.java
@@ -61,6 +61,7 @@ public class StarterServiceLifeCycleSM {
machine.lifeCycleProxy = (ServiceLifeCycle) machine.eventProxy;
return machine.lifeCycleProxy;
}
+
@State({Idle.class, Preparing.class, Prepared.class, Starting.class,
Failed.class, Running.class, Stopping.class, DirtyShutdown.class,
Idle.class})
http://git-wip-us.apache.org/repos/asf/river-container/blob/60c5c7fe/river-container-core/src/main/java/org/apache/river/container/deployer/StartupDeployer.java
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/java/org/apache/river/container/deployer/StartupDeployer.java b/river-container-core/src/main/java/org/apache/river/container/deployer/StartupDeployer.java
index 2a96978..26e5598 100644
--- a/river-container-core/src/main/java/org/apache/river/container/deployer/StartupDeployer.java
+++ b/river-container-core/src/main/java/org/apache/river/container/deployer/StartupDeployer.java
@@ -19,16 +19,21 @@ package org.apache.river.container.deployer;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
import javax.management.MBeanRegistrationException;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileType;
import org.apache.river.container.ConfigurationException;
import org.apache.river.container.Context;
@@ -48,28 +53,55 @@ import org.apache.river.container.Utils;
*/
public class StartupDeployer {
- private static final Logger log =
- Logger.getLogger(StartupDeployer.class.getName(), MessageNames.BUNDLE_NAME);
-
+ private static final Logger log
+ = Logger.getLogger(StartupDeployer.class.getName(), MessageNames.BUNDLE_NAME);
+
private String deployDirectory = org.apache.river.container.Strings.DEFAULT_DEPLOY_DIRECTORY;
-
+
@Injected(style = InjectionStyle.BY_TYPE)
private FileUtility fileUtility = null;
-
+
@Injected(style = InjectionStyle.BY_TYPE)
private Context context;
-
+
@Injected(style = InjectionStyle.BY_TYPE)
private StarterServiceDeployer deployer;
-
+
@Injected(style = InjectionStyle.BY_TYPE)
private MBeanRegistrar mbeanRegistrar;
-
+
@Name
private String myName = null;
- private List<ApplicationEnvironment> applicationEnvironments =
- new ArrayList<ApplicationEnvironment>();
+ private Map<String, DeploymentRecord> deployedServices = new HashMap<String, DeploymentRecord>();
+
+ private class DeploymentRecord {
+
+ String name;
+ long updateTime;
+ FileObject fileObject;
+ ServiceLifeCycle serviceLifeCycle;
+ }
+
+ private boolean autoDeploy = false;
+
+ public boolean isAutoDeploy() {
+ return autoDeploy;
+ }
+
+ public void setAutoDeploy(boolean autoDeploy) {
+ this.autoDeploy = autoDeploy;
+ }
+
+ public int getScanInterval() {
+ return scanInterval;
+ }
+
+ public void setScanInterval(int scanInterval) {
+ this.scanInterval = scanInterval;
+ }
+
+ private int scanInterval = 5;
public String getDeployDirectory() {
return deployDirectory;
@@ -79,8 +111,8 @@ public class StartupDeployer {
this.deployDirectory = deployDirectory;
}
- FileObject deploymentDirectoryFile=null;
-
+ FileObject deploymentDirectoryFile = null;
+
@Init
public void init() {
try {
@@ -105,52 +137,139 @@ public class StartupDeployer {
new Object[]{deployDirectory, fileUtility.getProfileDirectory()});
}
/*
- Go through the deployment directory looking for services to deploy.
+ Do the scan task once - this will launch all the services currently in
+ deploy dir.
*/
- List<FileObject> serviceArchives =
- Utils.findChildrenWithSuffix(deploymentDirectoryFile,
- org.apache.river.container.Strings.JAR);
- if (serviceArchives != null) {
- log.log(Level.FINE, MessageNames.FOUND_SERVICE_ARCHIVES,
- new Object[]{serviceArchives.size(), deployDirectory});
- deployServiceArchives(serviceArchives);
- } else {
- log.log(Level.WARNING, MessageNames.FOUND_NO_SERVICE_ARCHIVES,
- new Object[]{deployDirectory});
+ new ScanTask().runOnce();
+ if (autoDeploy) {
+ /* Now schedule a scan in the required scan time. */
+ deployer.workManager.schedule(null, new ScanTask(), getScanInterval(), TimeUnit.SECONDS);
}
+ }
+ private void registerApplication(ServiceLifeCycle deployedApp) throws MalformedObjectNameException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put(org.apache.river.container.Strings.NAME, deployedApp.getName());
+ ObjectName oName = new ObjectName(org.apache.river.container.Strings.CONTAINER_JMX_DOMAIN, props);
+ mbeanRegistrar.getMbeanServer().registerMBean(
+ deployedApp, oName);
}
- private void deployServiceArchives(List<FileObject> serviceArchives) {
+ private void unregisterApplication(ServiceLifeCycle deployedApp) {
+ try {
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put(org.apache.river.container.Strings.NAME, deployedApp.getName());
+ ObjectName oName = new ObjectName(org.apache.river.container.Strings.CONTAINER_JMX_DOMAIN, props);
+ mbeanRegistrar.getMbeanServer().unregisterMBean(oName);
+ } catch (Exception e) {
+ log.log(Level.SEVERE, MessageNames.FAILED_TO_REMOVE_MBEAN,
+ new Object[]{deployedApp.getName()});
+ }
+ }
+
+ private Map<String, DeploymentRecord> scanDeploymentArchives() throws FileSystemException {
/*
- Deploy those services.
+ Go through the deployment directory looking for services to deploy.
*/
- for (FileObject archiveFile : serviceArchives) {
+ Map<String, DeploymentRecord> deployDirListing = new HashMap<String, DeploymentRecord>();
+ deploymentDirectoryFile.refresh();
+ List<FileObject> serviceArchives
+ = Utils.findChildrenWithSuffix(deploymentDirectoryFile,
+ org.apache.river.container.Strings.JAR);
+ if (serviceArchives != null) {
+ log.log(Level.FINER, MessageNames.FOUND_SERVICE_ARCHIVES,
+ new Object[]{serviceArchives.size(), deployDirectory});
+ for (FileObject serviceArchive : serviceArchives) {
+ DeploymentRecord rec = new DeploymentRecord();
+ rec.fileObject = serviceArchive;
+ rec.name = serviceArchive.getName().getBaseName();
+ rec.updateTime = serviceArchive.getContent().getLastModifiedTime();
+ deployDirListing.put(rec.name, rec);
+ }
+ }
+ return deployDirListing;
+ }
+
+ private class ScanTask implements Runnable {
+
+ public void runOnce() {
try {
- /* Try the archive in all the deployers to see if someone can
- * handle it. For now there's only one.
- */
-
- /*
- * Create the ApplicationEnvironment for the archive.
- */
- ServiceLifeCycle deployedApp=deployer.deployServiceArchive(archiveFile);
- // Register it as an MBean
- registerApplication(deployedApp);
- deployedApp.start();
+ log.log(Level.FINER, MessageNames.SCANNING_DEPLOYMENT_DIRECTORY,
+ new Object[]{deployDirectory});
+ Map<String, DeploymentRecord> deployDirListing = scanDeploymentArchives();
+ // DeployDirListing will become the deployedServices collection
+ synchDeployedServices(deployedServices, deployDirListing);
} catch (Throwable t) {
- log.log(Level.WARNING, MessageNames.FAILED_DEPLOY_SERVICE, archiveFile.toString());
- log.log(Level.WARNING, MessageNames.EXCEPTION_THROWN, Utils.stackTrace(t));
+ t.printStackTrace();
}
}
+
+ public void run() {
+ runOnce();
+ deployer.workManager.schedule(null, this, scanInterval, TimeUnit.SECONDS);
+ }
}
-
- private void registerApplication(ServiceLifeCycle deployedApp) throws MalformedObjectNameException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
- Hashtable<String, String> props=new Hashtable<String,String>();
- props.put(org.apache.river.container.Strings.NAME, deployedApp.getName());
- ObjectName oName=new ObjectName(org.apache.river.container.Strings.CONTAINER_JMX_DOMAIN, props);
- mbeanRegistrar.getMbeanServer().registerMBean(
- deployedApp, oName);
+
+ private void synchDeployedServices(Map<String, DeploymentRecord> currentList,
+ Map<String, DeploymentRecord> newList) {
+ // For each entry
+ for (DeploymentRecord rec : newList.values()) {
+ // If it isn't already in deployedServices, start it
+ DeploymentRecord current = currentList.get(rec.name);
+ if (current == null) {
+ log.log(Level.FINE, MessageNames.STARTING_SERVICE,
+ new Object[]{rec.name});
+ currentList.put(rec.name, rec);
+ deployAndStart(rec);
+ } else if (current.updateTime != rec.updateTime) {
+ // If it's in deployedServices but now newer, stop and restart
+ log.log(Level.FINE, MessageNames.UPDATING_SERVICE,
+ new Object[]{rec.name});
+ currentList.remove(current.name);
+ stopAndRemove(current);
+ currentList.put(rec.name, rec);
+ deployAndStart(rec);
+ }
+ }
+ // If there are any services left in deployedServices, stop them
+ List<DeploymentRecord> removals = new ArrayList<DeploymentRecord>();
+ for (DeploymentRecord current : currentList.values()) {
+ if (!newList.containsKey(current.name)) {
+ removals.add(current);
+ }
+ }
+ for (DeploymentRecord current : removals) {
+ log.log(Level.FINE, MessageNames.STOPPING_SERVICE,
+ new Object[]{current.name});
+ currentList.remove(current.name);
+ stopAndRemove(current);
+ }
+
+ }
+
+ private void deployAndStart(DeploymentRecord dr) {
+ try {
+ /* Try the archive in all the deployers to see if someone can
+ * handle it. For now there's only one.
+ */
+
+ /*
+ * Create the ApplicationEnvironment for the archive.
+ */
+ dr.serviceLifeCycle = deployer.deployServiceArchive(dr.fileObject);
+ // Register it as an MBean
+ registerApplication(dr.serviceLifeCycle);
+ dr.serviceLifeCycle.start();
+ } catch (Throwable t) {
+ log.log(Level.WARNING, MessageNames.FAILED_DEPLOY_SERVICE, dr.name);
+ log.log(Level.WARNING, MessageNames.EXCEPTION_THROWN, Utils.stackTrace(t));
+ }
+
+ }
+
+ private void stopAndRemove(DeploymentRecord dr) {
+ dr.serviceLifeCycle.stop();
+ unregisterApplication(dr.serviceLifeCycle);
}
}
http://git-wip-us.apache.org/repos/asf/river-container/blob/60c5c7fe/river-container-core/src/main/resources/org/apache/river/container/Messages.properties
----------------------------------------------------------------------
diff --git a/river-container-core/src/main/resources/org/apache/river/container/Messages.properties b/river-container-core/src/main/resources/org/apache/river/container/Messages.properties
index e80be2b..7a93455 100644
--- a/river-container-core/src/main/resources/org/apache/river/container/Messages.properties
+++ b/river-container-core/src/main/resources/org/apache/river/container/Messages.properties
@@ -21,6 +21,8 @@ addingClasspathEntry=Adding classpath entry ''{0}''.
annotatedObjectDeployerHasUnresolvedDependencies=Initialization failed because \
one or more dependencies flagged with @Injected or @Name annotations \
are unresolved.
+autoDeployerFailedInit=Automatic Starter-Service deployer has failed to initialize.
+autoDeployerStarting=Automatic deployer service is starting up.
badClasspathExpression=Bad Classpath Expression {0} {1}.
badMemberForInjectedAnnotation=@Injected annotation must be applied to a field or\
setter method only: Member {1} on class {0} doesn't qualify.
@@ -58,6 +60,8 @@ exceptionWhileStopping=Exception thrown during stop operation:\n{0}
failedCleanShutdown=Application ''{0}'' failed to shutdown cleanly, so we're interrupting it.
failedDeployService=Deployment of service archive at ''{0}'' failed.
failedReadProperties=Failed to read one or more properties files.
+failedToRemoveMBean=Failed to remove MBean for application ''{0}''.
+failedToSetProperty=Failed to set property ''{0}'' on component class ''{1}'' to ''{2}''.
foundNoServiceArchives=Found no service archives for deployment dir ''{0}''.
foundServiceArchives=Found {0} service archives in deployment dir ''{1}''.
illegalArgumentException=An operation threw an IllegalArgumentException.
@@ -93,10 +97,12 @@ readingObject.annotatedMemberFound=Member ''{0}'' is annotated @Injected.
readingObject.nonAnnotatedMemberFound=Member ''{0}'' is not annotated @Injected.
receivedStart=Received start event while in state {0}.
receivedStartWithArgs=Received start with arguments event while in state {0}.
+scanningDeploymentDirectory=Scanning deployment directory ''{0}''.
securityInitializationFailed=Failed to initialize security subsystem.
securityInitializationSucceeded=Security Manager and Dynamic Policy successfully installed.
securityInitializationWrongPolicy=After security manager setup, the wrong policy is installed: {0}.
serviceParentClassloaderIs=Parent of service classloader is {0}.
+setPropertyOnComponent=Property ''{0}'' on component {1}''{2}'' was set to ''{3}''.
showCommandLineArguments=Command line arguments were: {0}.
shutdownFailed=Application ''{0}'' has failed to shut down - there are threads still running.
shutdownMethodHasParameters=A method flagged as @Shutdown must take no parameters. \
@@ -108,12 +114,15 @@ starterServiceDeployerInitialized=Starter-Service deployer named ''{0}'' complet
initialization.
starterServiceDeployerStarting=Starter-Service deployer named ''{0}'' is being \
initialized.
+startingService=Starting service ''{0}''.
startupDeployerFailedInit=Starter-Service deployer has failed to initialize.
startupDeployerInitialized=Starter-Service deployer named ''{0}'' completed \
initialization.
startupDeployerStarting=Starter-Service deployer named ''{0}'' is being \
initialized.
+stoppingService=Stopping service ''{0}''.
systemClassLoaderIs=System classloader is ''{0}'' with classpath {1}.
unresolvedDependency=Object {0} has an unresolved dependent member ''{1}'' \
(name=''{2}'').
unsupportedElement=Element type {0} is currently unsupported.
+updatingService=Updating service ''{0}''.