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 2011/01/20 16:29:28 UTC

svn commit: r1061342 - in /incubator/river/jtsk/skunk/surrogate/src: org/apache/river/container/ schemas/

Author: gtrasuk
Date: Thu Jan 20 15:29:27 2011
New Revision: 1061342

URL: http://svn.apache.org/viewvc?rev=1061342&view=rev
Log:
Ongoing work.

Added:
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/CommandLineArgumentParser.java
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/FileUtility.java
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/FileUtilityImpl.java
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Name.java
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ProfileConfigReader.java
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ServiceStarterArchiveFileFilter.java
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/StarterServiceDeployer.java
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/core-config.xml
Modified:
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/AnnotatedClassDeployer.java
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Bootstrap.java
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Context.java
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ContextListener.java
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Host.java
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/MessageNames.java
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Messages.properties
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/SettableCodebaseClassLoader.java
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ShowContextToConsole.java
    incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Strings.java
    incubator/river/jtsk/skunk/surrogate/src/schemas/config.xsd

Modified: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/AnnotatedClassDeployer.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/AnnotatedClassDeployer.java?rev=1061342&r1=1061341&r2=1061342&view=diff
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/AnnotatedClassDeployer.java (original)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/AnnotatedClassDeployer.java Thu Jan 20 15:29:27 2011
@@ -15,9 +15,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.river.container;
 
+import java.beans.Introspector;
 import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
@@ -45,15 +45,15 @@ public class AnnotatedClassDeployer impl
             new ArrayList<DeployedObject>();
     private Map<String, DeployedObject> initializedObjects =
             new HashMap<String, DeployedObject>();
-    private List<DeploymentListener> deploymentListeners=
+    private List<DeploymentListener> deploymentListeners =
             new ArrayList<DeploymentListener>();
 
     public void put(String name, Object o) {
-        /*
-        Scan the object's class and register any injection needs from it.
-         */
-        readInObject(name, o);
         try {
+            /*
+            Scan the object's class and register any injection needs from it.
+             */
+            readInObject(name, o);
             /* Attempt to satisfy the object's injection needs from current
             candidates.
              */
@@ -81,29 +81,65 @@ public class AnnotatedClassDeployer impl
         this.context = ctx;
     }
 
-    private void initializeIfFullyResolved(DeployedObject deployed) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+    /** 
+    When the context notifies us that it is done reading the initialization
+    file, etc, then we can inject default values, check for unresolved
+    dependencies, etc.
+     */
+    public void initComplete() {
+        checkUnresolvedDependencies();
+    }
+
+    private void checkUnresolvedDependencies() {
+        if (uninitializedObjects.isEmpty()) {
+            return;
+        }
+
+        for (DeployedObject depObj : uninitializedObjects) {
+            for (Member m : depObj.getUnresolvedDependencies()) {
+                log.log(Level.SEVERE,
+                        MessageNames.UNRESOLVED_DEPENDENCY,
+                        new Object[]{depObj.getName(),
+                            m.getName(), nameAnnotation(m)});
+            }
+        }
+        throw new ConfigurationException(MessageNames.ANNOTATED_OBJECT_DEPLOYER_HAS_UNRESOLVED_DEPENDENCIES);
+    }
+
+    /**
+    Given an object, see if it is fully resolved (no outstanding dependencies).
+    If it is, then call any initialization that may be required, and move it
+    to our list of 'ready' objects.
+    @param deployed
+    @return True if the list of 'ready' objects has been changed.
+    @throws IllegalAccessException
+    @throws IllegalArgumentException
+    @throws InvocationTargetException
+     */
+    private boolean initializeIfFullyResolved(DeployedObject deployed) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
         if (deployed.getUnresolvedDependencies().isEmpty()) {
-            for(Method initMethod: deployed.getInitMethods()) {
+            uninitializedObjects.remove(deployed);
+            for (Method initMethod : deployed.getInitMethods()) {
                 initMethod.invoke(deployed.getDeployedObject());
             }
             notifyDeploymentListeners(deployed);
-            uninitializedObjects.remove(deployed);
             initializedObjects.put(deployed.getName(), deployed);
-            if(deployed.getDeployedObject() instanceof DeploymentListener){
-                deploymentListeners.add((DeploymentListener)
-                        deployed.getDeployedObject());
+            if (deployed.getDeployedObject() instanceof DeploymentListener) {
+                deploymentListeners.add((DeploymentListener) deployed.getDeployedObject());
             }
+            return true;
         }
+        return false;
     }
 
     private void notifyDeploymentListeners(DeployedObject deployed) {
-        for (DeploymentListener l: deploymentListeners) {
+        for (DeploymentListener l : deploymentListeners) {
             l.postInit(deployed.getName(), deployed.getDeployedObject());
         }
     }
 
-    private void readInObject(String name, Object o) {
-        log.log(Level.FINER, 
+    private void readInObject(String name, Object o) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+        log.log(Level.FINER,
                 MessageNames.READING_OBJECT,
                 new Object[]{name, o.getClass().getName()});
 
@@ -126,8 +162,15 @@ public class AnnotatedClassDeployer impl
             if (isInitMethod(m)) {
                 deployed.getInitMethods().add((Method) m);
             }
+            if (isAnnotatedAsName(m)) {
+                memberSet(deployed.getDeployedObject(), m, deployed.getName());
+            }
         }
-        /* Add the object and list to our unsatisfied group. */
+        /* Add the object
+        and list to our unsatisfied group. If it has no dependencies, then it
+        will be initialized and moved over to the initialized group when
+        resolve() is called.
+         */
         uninitializedObjects.add(deployed);
     }
 
@@ -147,17 +190,17 @@ public class AnnotatedClassDeployer impl
         if (annEm.getAnnotation(Init.class) == null) {
             return false;
         }
-        Method method=(Method) m;
+        Method method = (Method) m;
         if (method.getReturnType() != void.class) {
             throw new ConfigurationException(MessageNames.INIT_METHOD_NOT_VOID,
-                        m.getDeclaringClass().getName(),
-                        m.getName(),
-                        method.getReturnType());
+                    m.getDeclaringClass().getName(),
+                    m.getName(),
+                    method.getReturnType());
         }
         if (method.getParameterTypes().length != 0) {
             throw new ConfigurationException(MessageNames.INIT_METHOD_HAS_PARAMETERS,
-                        m.getDeclaringClass().getName(),
-                        m.getName());
+                    m.getDeclaringClass().getName(),
+                    m.getName());
         }
         return true;
     }
@@ -170,6 +213,25 @@ public class AnnotatedClassDeployer impl
             }
             if (m instanceof Method && m.getName().startsWith(Strings.SET)) {
                 return true;
+            } else {
+                throw new ConfigurationException(MessageNames.BAD_MEMBER_FOR_INJECTED_ANNOTATION, m.getDeclaringClass(), m.getName());
+            }
+        }
+        return false;
+    }
+
+    private boolean isAnnotatedAsName(Member m) {
+        AnnotatedElement annEm = (AnnotatedElement) m;
+        if (annEm.getAnnotation(Name.class) != null) {
+            if (m instanceof Field && ((Field) m).getType() == String.class) {
+                return true;
+            }
+            if (m instanceof Method && m.getName().startsWith(Strings.SET)
+                    && ((Method) m).getParameterTypes().length == 1
+                    && ((Method) m).getParameterTypes()[0] == String.class) {
+                return true;
+            } else {
+                throw new ConfigurationException(MessageNames.BAD_MEMBER_FOR_NAME_ANNOTATION, m.getDeclaringClass(), m.getName());
             }
         }
         return false;
@@ -186,9 +248,13 @@ public class AnnotatedClassDeployer impl
         return value == null;
     }
 
+    /** Build a list of members that might be candidates for injection.
+
+    @param cls
+    @return
+    @throws SecurityException
+     */
     List<Member> buildMemberList(Class cls) throws SecurityException {
-        /* Construct a list of unsatisfied dependencies from the object.
-         */
         List<Member> members = new ArrayList<Member>();
         members.addAll(Arrays.asList(cls.getDeclaredMethods()));
         members.addAll(Arrays.asList(cls.getDeclaredFields()));
@@ -202,43 +268,60 @@ public class AnnotatedClassDeployer impl
     private void resolve() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
         boolean changed;
         do {
-            changed=false;
+            changed = false;
             /* For each object in the unsatisfied group, */
             /* Group of uninitialized objects may change while we're going
             through them, so use a copy of the array.
              */
             for (DeployedObject deployed : new ArrayList<DeployedObject>(uninitializedObjects)) {
-                /* Attempt to resolve unsatisfied dependencies. */
-                for (Member m : new ArrayList<Member>(deployed.getUnresolvedDependencies())) {
-                    /* If there's a name annotated, lookup by name. */
-                    String name = nameAnnotation(m);
-                    Object val = null;
-                    if (!name.equals(Strings.EMPTY)) {
-                        DeployedObject deployedCandidate= initializedObjects.get(name);
-                        if (deployedCandidate!=null) {
-                            val=deployedCandidate.getDeployedObject();
-                        }
-                    } else {
-                        val = findAssignable(m);
-                    }
-                    if (val != null) {
-                        changed=true;
-                        inject(deployed, m, val);
-                        removeDependencyFromUnresolvedList(deployed, m);
-                    }
-                }
-                /* If satisfied, remove from unsatisfied group and
-                put into candidate group, then initialize. */
-                initializeIfFullyResolved(deployed);
+                changed = resolveDeployedObject(deployed);
             }
         } while (changed);
 
     }
 
+    private boolean resolveDeployedObject(DeployedObject deployed) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+        /* Attempt to resolve unsatisfied dependencies. */
+        for (Member m : new ArrayList<Member>(deployed.getUnresolvedDependencies())) {
+            /* First attempt lookup by name. */
+            String name = nameAnnotation(m);
+            Object val = null;
+            DeployedObject deployedCandidate = initializedObjects.get(name);
+            if (deployedCandidate != null) {
+                val = deployedCandidate.getDeployedObject();
+            } else {
+                /* Find a type-compatible object if name lookup fails. */
+                val = findAssignable(m);
+            }
+            if (val != null) {
+                inject(deployed, m, val);
+                removeDependencyFromUnresolvedList(deployed, m);
+            }
+        }
+        /* If satisfied, remove from unsatisfied group and
+        put into candidate group, then initialize. */
+        boolean changed = initializeIfFullyResolved(deployed);
+        return changed;
+    }
+
     private String nameAnnotation(Member m) {
         AnnotatedElement annEm = (AnnotatedElement) m;
         Injected inj = (Injected) annEm.getAnnotation(Injected.class);
-        return inj.value();
+        if (inj.value() != null && !Strings.EMPTY.equals(inj.value())) {
+            return inj.value();
+        }
+        if (m instanceof Field) {
+            return ((Field) m).getName();
+        }
+        if (m instanceof Method) {
+            String methodName = m.getName();
+            if (methodName.startsWith(Strings.SET)) {
+                /* Strip off 'set' and decapitalize the remainder according
+                to JavaBeans spec. */
+                return Introspector.decapitalize(methodName.substring(3));
+            }
+        }
+        return null;
     }
 
     /**
@@ -257,16 +340,43 @@ public class AnnotatedClassDeployer impl
             requiredType = ((Field) m).getType();
         }
 
-        if (Context.class.isAssignableFrom(requiredType)) {
+        /* Don't do injection by type on value types or String. */
+        if (isSimpleType(requiredType)) {
+            return null;
+        }
+        if (requiredType.isAssignableFrom(Context.class)) {
             return context;
         }
-        for (DeployedObject candidate: initializedObjects.values()) {
-            if (candidate.getDeployedObject().getClass().isAssignableFrom(requiredType)) {
+        for (DeployedObject candidate : initializedObjects.values()) {
+            if (requiredType.isAssignableFrom(candidate.getDeployedObject().getClass())) {
                 return candidate.getDeployedObject();
             }
         }
         return null;
     }
+    private Class[] simpleTypes = {
+        boolean.class,
+        int.class,
+        long.class,
+        float.class,
+        double.class,
+        Boolean.class,
+        Integer.class,
+        Long.class,
+        Float.class,
+        Double.class,
+        java.util.Date.class,
+        String.class
+    };
+
+    private boolean isSimpleType(Class type) {
+        for (Class simpleType : simpleTypes) {
+            if (type == simpleType) {
+                return true;
+            }
+        }
+        return false;
+    }
 
     /** Inject a resolved value into the deployed object.
     After the injection is complete, remove the member from our list of
@@ -279,7 +389,7 @@ public class AnnotatedClassDeployer impl
     @param val The value to set.
      */
     private void inject(DeployedObject deployed, Member m, Object val) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
-        log.log(Level.FINER, 
+        log.log(Level.FINER,
                 MessageNames.INJECT,
                 new Object[]{deployed.getName(), m.getName(), val});
         memberSet(deployed.getDeployedObject(), m, val);
@@ -288,13 +398,13 @@ public class AnnotatedClassDeployer impl
     private void memberSet(Object target, Member member, Object value) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
         if (member instanceof Field) {
             Field f = (Field) member;
-            boolean originalAccess=f.isAccessible();
+            boolean originalAccess = f.isAccessible();
             f.setAccessible(true);
             f.set(target, value);
             f.setAccessible(originalAccess);
         } else {
             Method m = (Method) member;
-            boolean originalAccess=m.isAccessible();
+            boolean originalAccess = m.isAccessible();
             m.setAccessible(true);
             m.invoke(target, value);
             m.setAccessible(originalAccess);

Modified: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Bootstrap.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Bootstrap.java?rev=1061342&r1=1061341&r2=1061342&view=diff
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Bootstrap.java (original)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Bootstrap.java Thu Jan 20 15:29:27 2011
@@ -17,8 +17,8 @@
  */
 package org.apache.river.container;
 
+import java.beans.Statement;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.InputStream;
 import java.lang.reflect.InvocationTargetException;
@@ -65,11 +65,14 @@ those beans to setup and initialize them
 public class Bootstrap {
 
     private static final Logger log =
-            Logger.getLogger(Bootstrap.class.getName(),MessageNames.BUNDLE_NAME);
+            Logger.getLogger(Bootstrap.class.getName(), MessageNames.BUNDLE_NAME);
 
     public static void main(String args[]) {
         try {
             initializeContainer(args);
+        } catch (InvocationTargetException ex) {
+            log.log(Level.SEVERE, MessageNames.INITIALIZATION_EXCEPTION, ex.getCause());
+            System.exit(-1);
         } catch (Exception ex) {
             log.log(Level.SEVERE, MessageNames.INITIALIZATION_EXCEPTION, ex);
             System.exit(-1);
@@ -97,24 +100,14 @@ public class Bootstrap {
         return urls;
     }
 
-    static void initializeContainer(String args[]) throws SAXException, JAXBException, FileNotFoundException, MalformedURLException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
-        Unmarshaller um = createConfigUnmarshaller();
-
-        /* If there is a first argument, and it doesn't begin with '-', then
-        it's a profile name.
-         */
-        String profileName = Strings.DEFAULT;
-        if (args.length > 0 && !args[0].startsWith(Strings.DASH)) {
-            profileName = args[0];
-        }
-        File profileDir =
-                new File(Strings.PROFILE + File.separator + profileName);
-        File configFile = new File(profileDir, Strings.CONFIG_XML);
-        InputStream is = new FileInputStream(configFile);
-        ContainerConfig containerConfig = (ContainerConfig) um.unmarshal(is);
-        URL[] urls = findClasspathURLS(containerConfig);
-        log.log(Level.INFO, MessageNames.CONFIGURED_CLASSPATH, new Object[] {
-            Utils.format(urls) } );
+    static void initializeContainer(String args[]) throws SAXException, JAXBException, FileNotFoundException, MalformedURLException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException, ConfigurationException, Exception {
+        //Logger.getLogger("org.apache.river.container.AnnotatedClassDeployer").setLevel(Level.ALL);
+        Logger.getLogger(CommandLineArgumentParser.class.getName()).setLevel(Level.ALL);
+        
+        ContainerConfig coreConfig = readCoreConfig();
+        URL[] urls = findClasspathURLS(coreConfig);
+        log.log(Level.INFO, MessageNames.CONFIGURED_CLASSPATH, new Object[]{
+                    Utils.format(urls)});
         /* Setup the classloader using the parent of the bootstrap's classloader,
         which should be the extension loader.
          */
@@ -122,37 +115,79 @@ public class Bootstrap {
                 Bootstrap.class.getClassLoader().getParent());
         /* Create the context object. */
         Object context = Class.forName(Strings.CONTEXT_CLASS, true, classLoader).newInstance();
-        Method putMethod = context.getClass().getMethod(Strings.PUT, new Class[]{Object.class});
         Method putByNameMethod = context.getClass().getMethod(
-                Strings.PUT, new Class[] { String.class, Object.class});
-        putMethod.invoke(context, (Object) args);
+                Strings.PUT, new Class[]{String.class, Object.class});
+        Method initCompleteMethod = context.getClass().getMethod(Strings.INIT_COMPLETE, new Class[0]);
         Thread.currentThread().setContextClassLoader(classLoader);
-        for (Object element : containerConfig.getElements()) {
-            if (element instanceof Component) {
-                Component c = (Component) element;
-                Class compClass = Class.forName(c.getClazz(), true, classLoader);
-                Object instance = compClass.newInstance();
+        /* Process the core configuration */
+        processConfiguration(coreConfig, classLoader, context);
+        /* We need to set the command line args after processing the core
+         configuration so that the items in the core-config get initialized.
+         */
+        putByNameMethod.invoke(context, Strings.COMMAND_LINE_ARGS, (Object) args);
+        /* The core configuration now loads the profile configuration... */
+        // processConfiguration(containerConfig, classLoader, putMethod, context, putByNameMethod);
+        initCompleteMethod.invoke(context, new Object[0]);
+    }
+
+    static void processConfiguration(ContainerConfig config, Object classLoader, Object context) throws InvocationTargetException, ConfigurationException, IllegalArgumentException, InstantiationException, ClassNotFoundException, IllegalAccessException, NoSuchMethodException, MalformedURLException, Exception {
+        Method putMethod = context.getClass().getMethod(Strings.PUT, new Class[]{Object.class});
+        Method putByNameMethod = context.getClass().getMethod(
+                Strings.PUT, new Class[]{String.class, Object.class});
+
+        /* Add the classpath urls found in the configuration into the
+         classloader.
+         Note that we have to do this by reflection because the classloader
+         we're handed may not be the same classloader that loaded this instance
+         of the Bootstrap class.  In particular, this occurs when we are loading
+         the profile configuration by calling out ProfileConfigReader in
+         core-config.xml.  In that case, the container classloader is created
+         by the original Bootstrap class inside the original classloader, but
+         ProfileConfigReader and hence another Bootstrap class gets loaded by
+         the container class loader.
+         */
+        for(URL url: findClasspathURLS(config)) {
+            new Statement(classLoader, Strings.ADD_URL, new Object[] {url})
+            .execute();
+        }
+        for (Object element : config.getElements()) {
+            processElement(element, (ClassLoader) classLoader, putMethod, context, putByNameMethod);
+        }
+    }
+
+    private static ContainerConfig readCoreConfig() throws SAXException, JAXBException, FileNotFoundException {
+        Unmarshaller um = createConfigUnmarshaller();
+        InputStream is = Bootstrap.class.getResourceAsStream(Strings.CORE_CONFIG_XML);
+        ContainerConfig containerConfig = (ContainerConfig) um.unmarshal(is);
+        return containerConfig;
+    }
+
+    private static void processElement(Object element, ClassLoader classLoader, Method putMethod, Object context, Method putByNameMethod) throws ClassNotFoundException, InstantiationException, InvocationTargetException, ConfigurationException, IllegalAccessException, IllegalArgumentException {
+        if (element instanceof Component) {
+            Component c = (Component) element;
+            Class compClass = Class.forName(c.getClazz(), true, classLoader);
+            String name = c.getName();
+            Object instance = compClass.newInstance();
+            if (name == null || name.trim().length() == 0) {
                 putMethod.invoke(context, instance);
-            } else if (element instanceof Property) {
-                Property p=(Property) element;
-                putByNameMethod.invoke(context, p.getName(), p.getValue());
-            } else if(element instanceof DiscoveryContextType) {
-                /* Just drop the element into the context under the
-                 appropriate name.
-                 */
-                DiscoveryContextType dct=(DiscoveryContextType) element;
-                if (dct.getName() == null) {
-                   putByNameMethod.invoke(context,
-                           Strings.DEFAULT_DISCOVERY_CONTEXT,
-                           dct);
-                } else {
-                    putByNameMethod.invoke(context,
-                            dct.getName(),
-                            dct);
-                }
             } else {
-                throw new ConfigurationException(MessageNames.UNSUPPORTED_ELEMENT, element.getClass().getName());
+                putByNameMethod.invoke(context, name, instance);
+            }
+        } else if (element instanceof Property) {
+            Property p = (Property) element;
+            putByNameMethod.invoke(context, p.getName(), p.getValue());
+        } else if (element instanceof DiscoveryContextType) {
+            /* Just drop the element into the context under the
+            appropriate name.
+             */
+            DiscoveryContextType dct = (DiscoveryContextType) element;
+            if (dct.getName() == null) {
+                putByNameMethod.invoke(context, Strings.DEFAULT_DISCOVERY_CONTEXT, dct);
+            } else {
+                putByNameMethod.invoke(context, dct.getName(), dct);
             }
+        } else {
+            throw new ConfigurationException(MessageNames.UNSUPPORTED_ELEMENT, element.getClass().getName());
         }
     }
 
@@ -161,4 +196,15 @@ public class Bootstrap {
         URL[] urls = findClasspathURLS(classpathStr);
         return urls;
     }
+
+    private static void installAnnotatedClassDeployer(SettableCodebaseClassLoader classLoader,
+            Method putMethod, Object context) throws ClassNotFoundException, InstantiationException, InvocationTargetException, ConfigurationException, IllegalAccessException, IllegalArgumentException {
+        /* The following line looks funny, but makes sense:  we need to get an
+        instance of AnnotatedClassDeployer that is loaded from the container's
+        classloader rather than the bootstrap classloader.
+         */
+        Class compClass = Class.forName(AnnotatedClassDeployer.class.getName(), true, classLoader);
+        Object instance = compClass.newInstance();
+        putMethod.invoke(context, instance);
+    }
 }

Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/CommandLineArgumentParser.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/CommandLineArgumentParser.java?rev=1061342&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/CommandLineArgumentParser.java (added)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/CommandLineArgumentParser.java Thu Jan 20 15:29:27 2011
@@ -0,0 +1,60 @@
+/*
+ * 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.river.container;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ Processor that sets up various context items according to the command line
+ arguments supplied.
+ <p>
+ For one thing, this sets up the profile according to the first command-line
+ parameter.  If the first parameter is there and does not start with a '-',
+ it is used as the profile name.  Otherwise the profile name is set to
+ 'default'.
+ 
+ * @author trasukg
+ */
+public class CommandLineArgumentParser {
+    private static final Logger log=
+            Logger.getLogger(CommandLineArgumentParser.class.getName(),
+            MessageNames.BUNDLE_NAME);
+
+    @Injected
+    public String[] commandLineArguments=null;
+
+    @Injected
+    Context context=null;
+
+    @Init
+    public void init() {
+        /* If there is a first argument, and it doesn't begin with '-', then
+        it's a profile name.
+         */
+        String cmdString=Utils.format(commandLineArguments);
+        log.log(Level.FINE, MessageNames.SHOW_COMMAND_LINE_ARGUMENTS, cmdString);
+        if (commandLineArguments.length > 0 && !commandLineArguments[0].startsWith(Strings.DASH)) {
+            String profileName = commandLineArguments[0];
+            context.put(Strings.PROFILE, profileName);
+        } else {
+            context.put(Strings.PROFILE, Strings.DEFAULT);
+        }
+    }
+}

Modified: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Context.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Context.java?rev=1061342&r1=1061341&r2=1061342&view=diff
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Context.java (original)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Context.java Thu Jan 20 15:29:27 2011
@@ -52,8 +52,19 @@ public class Context {
          If the added object happens to implement ContextListener, it
          will be notified that it was added to the context.
          */
-        for (ContextListener l: listeners) {
+        for (ContextListener l: new ArrayList<ContextListener>(listeners)) {
             l.put(name, o);
         }
     }
+
+    /**
+     Called by the bootstrapper to tell us that processing of the initialization
+     file is now complete.
+     */
+    public void initComplete() {
+        for (ContextListener l: listeners) {
+            l.initComplete();
+        }
+
+    }
 }

Modified: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ContextListener.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ContextListener.java?rev=1061342&r1=1061341&r2=1061342&view=diff
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ContextListener.java (original)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ContextListener.java Thu Jan 20 15:29:27 2011
@@ -23,9 +23,28 @@ package org.apache.river.container;
  * @author trasukg
  */
 public interface ContextListener {
+
+    /**
+     Indicates that an object has been added to the context.
+     @param name
+     @param o
+     */
     public void put(String name, Object o);
 
+    /**
+     Indicates that an object has been removed from the context.
+     @param o
+     */
     public void remove(Object o);
 
+    /**
+     Informs the listener of the context object.
+     @param ctx
+     */
     public void setContext(Context ctx);
+
+    /**
+     Indicates that processing of any initialization file is complete.
+     */
+    public void initComplete();
 }

Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/FileUtility.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/FileUtility.java?rev=1061342&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/FileUtility.java (added)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/FileUtility.java Thu Jan 20 15:29:27 2011
@@ -0,0 +1,45 @@
+/*
+ * 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.river.container;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ *
+ * @author trasukg
+ */
+public interface FileUtility {
+    /**
+     Get a working directory with the given name.
+     @param name
+     @return
+     @throws IOException
+     */
+    public File getWorkingDirectory(String name) throws IOException;
+
+    /**
+     Get the 'home' directory for the current container profile.
+     @return
+     @throws IOException
+     */
+    public File getProfileDirectory() throws IOException;
+
+    
+}

Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/FileUtilityImpl.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/FileUtilityImpl.java?rev=1061342&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/FileUtilityImpl.java (added)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/FileUtilityImpl.java Thu Jan 20 15:29:27 2011
@@ -0,0 +1,47 @@
+/*
+ * 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.river.container;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ *
+ * @author trasukg
+ */
+public class FileUtilityImpl implements FileUtility {
+
+    @Injected
+    private String profile=null;
+
+    public File getWorkingDirectory(String name) throws IOException {
+
+        File workDir=new File(getProfileDirectory(), name);
+        if (!workDir.exists()) {
+            workDir.mkdirs();
+        }
+        return workDir;
+    }
+
+    public File getProfileDirectory() throws IOException {
+        File profileDir = new File(Strings.PROFILE + File.separator + profile);
+        return profileDir;
+    }
+
+}

Modified: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Host.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Host.java?rev=1061342&r1=1061341&r2=1061342&view=diff
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Host.java (original)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Host.java Thu Jan 20 15:29:27 2011
@@ -22,7 +22,10 @@ import java.util.ArrayList;
 import java.util.List;
 
 /**
- *
+ * This is from the early work on the surrogate host and was meant to be
+ the overall container.  At this point, it probably should be refactored or
+ removed and replaced with something that supports the Context-based deployers.
+
  * @author trasukg
  */
 public class Host {

Modified: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/MessageNames.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/MessageNames.java?rev=1061342&r1=1061341&r2=1061342&view=diff
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/MessageNames.java (original)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/MessageNames.java Thu Jan 20 15:29:27 2011
@@ -18,6 +18,21 @@
 
 package org.apache.river.container;
 
+/*
+ TODO: Should the messages be separated into different domains based on the
+ audience?  i.e. Should we have ExceptionMessages that might be seen by users
+ and LogMessages that are primarily meant to be seen by developers? UIMessages
+ that are assumed to be used in the UI?
+
+ Advantages:
+ - Possibly better organization
+ - Internationalization/Translation efforts could be more focused.
+
+ Also, should we assign a code to each message (msg number, etc)?  That way,
+ support tools could search an email message for the exception code and
+ then generate a list of candidate support messages.
+ */
+
 /**
  * Constants that hold message names used in the message resource bundle.
  * @author trasukg
@@ -26,8 +41,14 @@ public class MessageNames {
     public static final String BUNDLE_NAME="org.apache.river.container.Messages";
 
     public static final String
+            ANNOTATED_OBJECT_DEPLOYER_HAS_UNRESOLVED_DEPENDENCIES="annotatedObjectDeployerHasUnresolvedDependencies",
+            BAD_MEMBER_FOR_INJECTED_ANNOTATION="badMemberForInjectedAnnotation",
+            BAD_MEMBER_FOR_NAME_ANNOTATION="badMemberForNameAnnotation",
+            CONFIG_FILE="configFile",
             CONFIGURED_CLASSPATH = "configuredClasspath",
             CONTEXT_ITEM = "contextItem",
+            EXCEPTION_THROWN="exceptionThrown",
+            FAILED_DEPLOY_SERVICE="failedDeployService",
             ILLEGAL_ARGUMENT_EXCEPTION="illegalArgumentException",
             ILLEGAL_ACCESS_EXCEPTION="illegalAccessException",
             INITIALIZATION_EXCEPTION="initializationException",
@@ -35,9 +56,14 @@ public class MessageNames {
             INIT_METHOD_HAS_PARAMETERS="initMethodHasParameters",
             INIT_METHOD_NOT_VOID="initMethodIsntVoid",
             INJECT="inject",
+            PROFILE_CONFIG_EXCEPTION="profileConfigurationException",
             READING_OBJECT="readingObject",
             READING_OBJECT_MEMBER_COUNT="readingObject.memberCount",
             READING_OBJECT_ANNOTATED_MEMBER_FOUND="readingObject.annotatedMemberFound",
             READING_OBJECT_NON_ANNOTATED_MEMBER_FOUND="readingObject.nonAnnotatedMemberFound",
+            SHOW_COMMAND_LINE_ARGUMENTS="showCommandLineArguments",
+            STARTER_SERVICE_DEPLOYER_FAILED_INIT="starterServiceDeployerFailedInit",
+            STARTER_SERVICE_DEPLOYER_STARTING="starterServiceDeployerStarting",
+            UNRESOLVED_DEPENDENCY="unresolvedDependency",
             UNSUPPORTED_ELEMENT="unsupportedElement";
 }

Modified: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Messages.properties
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Messages.properties?rev=1061342&r1=1061341&r2=1061342&view=diff
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Messages.properties (original)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Messages.properties Thu Jan 20 15:29:27 2011
@@ -16,8 +16,18 @@
  * limitations under the License.
  */
 
+annotatedObjectDeployerHasUnresolvedDependencies=Initialization failed because \
+one or more dependencies flagged with @Injected or @Name annotations \
+are unresolved.
+badMemberForInjectedAnnotation=@Injected annotation must be applied to a field or\
+ setter method only: Member {1} on class {0} doesn't qualify.
+badMemberForNameAnnotation=@Name annotation must be applied to a String field or\
+ setter method only: Member {1} on class {0} doesn't qualify.
+configFile=Configuration file is ''{0}''.
 configuredClasspath=The configured classpath is {0}.
 contextItem=Context key {0} refers to ''{1}''.
+exceptionThrown=Exception thrown:
+failedDeployService=Deployment of service archive at ''{0}'' failed.
 illegalArgumentException=An operation threw an IllegalArgumentException.
 illegalAccessException=An operation threw an IllegalAccessException.
 invocationTargetException=An operation threw an InvocationTargetException.
@@ -27,8 +37,15 @@ Method ''{1}'' on class ''{0}'' has para
 initMethodIsntVoid=A method flagged as @Init must be void return type.  \
 Method ''{1}'' on class ''{0}'' returns ''{2}''.
 inject=Injecting {2} into member ''{1}'' of deployed object {0}.
+profileConfigurationException=Failed to read the configuration for profile {0}.
 readingObject=Reading instance of {1} named ''{0}'' for unresolved dependencies.
 readingObject.memberCount={0} members found.
 readingObject.annotatedMemberFound=Member ''{0}'' is annotated @Injected.
 readingObject.nonAnnotatedMemberFound=Member ''{0}'' is not annotated @Injected.
+showCommandLineArguments=Command line arguments were: {0}.
+starterServiceDeployerFailedInit=Starter-Service deployer has failed to initialize.
+starterServiceDeployerStarting=Starter-Service deployer named ''{0}'' is being \
+initialized.
+unresolvedDependency=Object {0} has an unresolved dependent member ''{1}'' \
+(name=''{2}'').
 unsupportedElement=Element type {0} is currently unsupported.

Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Name.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Name.java?rev=1061342&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Name.java (added)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Name.java Thu Jan 20 15:29:27 2011
@@ -0,0 +1,37 @@
+/*
+ * 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.river.container;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ Annotation used to flag a field or setter method that should be filled in
+ with the component's name on deployment.
+ * @author trasukg
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.METHOD})
+public @interface Name {
+
+}

Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ProfileConfigReader.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ProfileConfigReader.java?rev=1061342&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ProfileConfigReader.java (added)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ProfileConfigReader.java Thu Jan 20 15:29:27 2011
@@ -0,0 +1,58 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.apache.river.container;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import org.apache.river.container.config.ContainerConfig;
+import org.xml.sax.SAXException;
+
+/**
+ *
+ * @author trasukg
+ */
+public class ProfileConfigReader {
+
+    private static final Logger log =
+            Logger.getLogger(ProfileConfigReader.class.getName(), MessageNames.BUNDLE_NAME);
+
+    @Injected
+    private FileUtility fileUtility = null;
+    @Injected
+    private Context context = null;
+
+    @Injected private String profile=null;
+
+    private ContainerConfig readProfileConfig() throws SAXException, JAXBException, FileNotFoundException, IOException {
+        Unmarshaller um = Bootstrap.createConfigUnmarshaller();
+        File profileDir = fileUtility.getProfileDirectory();
+        File configFile = new File(profileDir, Strings.CONFIG_XML);
+        log.log(Level.INFO, MessageNames.CONFIG_FILE, configFile.getAbsolutePath());
+        InputStream is = new FileInputStream(configFile);
+        ContainerConfig containerConfig = (ContainerConfig) um.unmarshal(is);
+        return containerConfig;
+    }
+
+    @Init
+    public void init() {
+        try {
+            ContainerConfig profileConfig = readProfileConfig();
+            /* We use Object not ClassLoader because it might have been loaded
+             by a different classloader.
+             */
+            Object classLoader=this.getClass().getClassLoader();
+            Bootstrap.processConfiguration(profileConfig, classLoader, context);
+        } catch (Exception ex) {
+            throw new ConfigurationException(ex, MessageNames.PROFILE_CONFIG_EXCEPTION, profile);
+        }
+    }
+}

Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ServiceStarterArchiveFileFilter.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ServiceStarterArchiveFileFilter.java?rev=1061342&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ServiceStarterArchiveFileFilter.java (added)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ServiceStarterArchiveFileFilter.java Thu Jan 20 15:29:27 2011
@@ -0,0 +1,39 @@
+/*
+ * 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.river.container;
+
+import java.io.File;
+import java.io.FileFilter;
+
+/**
+ *
+ * @author trasukg
+ */
+public class ServiceStarterArchiveFileFilter implements FileFilter {
+
+    public boolean accept(File pathname) {
+        if (!pathname.isFile()) {
+            return false;
+        }
+        if (! pathname.getPath().endsWith(Strings.DOT_SSAR)) {
+            return false;
+        }
+        return true;
+    }
+
+}

Modified: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/SettableCodebaseClassLoader.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/SettableCodebaseClassLoader.java?rev=1061342&r1=1061341&r2=1061342&view=diff
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/SettableCodebaseClassLoader.java (original)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/SettableCodebaseClassLoader.java Thu Jan 20 15:29:27 2011
@@ -65,7 +65,7 @@ public class SettableCodebaseClassLoader
     /** Add a URL to this classpath.
      */
     @Override
-    protected void addURL(URL url) {
+    public void addURL(URL url) {
         URL[] currentURLS = super.getURLs();
         for (int i = 0; i < currentURLS.length; i++) {
             if (url.equals(currentURLS[i])) {

Modified: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ShowContextToConsole.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ShowContextToConsole.java?rev=1061342&r1=1061341&r2=1061342&view=diff
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ShowContextToConsole.java (original)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/ShowContextToConsole.java Thu Jan 20 15:29:27 2011
@@ -5,25 +5,41 @@
 
 package org.apache.river.container;
 
-import java.text.MessageFormat;
 import java.util.ResourceBundle;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 /**
  *
  * @author trasukg
  */
-public class ShowContextToConsole {
+public class ShowContextToConsole implements ContextListener {
 
-    @Injected private Context context;
+    private static final Logger log=Logger.getLogger(ShowContextToConsole.class.getName(), MessageNames.BUNDLE_NAME);
+
+    private Context context;
 
-    @Init
     public void init() {
-        ResourceBundle rb=ResourceBundle.getBundle(MessageNames.BUNDLE_NAME);
 
         for(String key: context.contents.keySet()) {
-            String out=MessageFormat.format(rb.getString(MessageNames.CONTEXT_ITEM),
-                    key, context.contents.get(key));
-            System.out.println(out);
+            log.log(Level.INFO,MessageNames.CONTEXT_ITEM ,
+                    new Object[] {key, context.contents.get(key)});
         }
     }
+
+    public void put(String name, Object o) {
+
+    }
+
+    public void remove(Object o) {
+
+    }
+
+    public void setContext(Context ctx) {
+        context=ctx;
+    }
+
+    public void initComplete() {
+        init();
+    }
 }

Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/StarterServiceDeployer.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/StarterServiceDeployer.java?rev=1061342&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/StarterServiceDeployer.java (added)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/StarterServiceDeployer.java Thu Jan 20 15:29:27 2011
@@ -0,0 +1,97 @@
+/*
+ * 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.river.container;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author trasukg
+ */
+public class StarterServiceDeployer {
+    private static final Logger log=
+            Logger.getLogger(StarterServiceDeployer.class.getName(), MessageNames.BUNDLE_NAME);
+    @Injected private FileUtility fileUtility=null;
+
+    @Name private String myName=null;
+
+    @Injected()
+    private String deploymentDirectory=null;
+
+    private File deploymentDirectoryFile=null;
+
+    private File workingDirectory=null;
+
+    @Init public void init() {
+        try {
+            tryInitialize();
+        } catch (Exception ex) {
+            throw new ConfigurationException(ex,
+                    MessageNames.STARTER_SERVICE_DEPLOYER_FAILED_INIT);
+        }
+    }
+
+    private void tryInitialize() throws IOException {
+        log.log(Level.INFO, MessageNames.STARTER_SERVICE_DEPLOYER_STARTING, myName);
+        /* Setup the working directory. */
+        workingDirectory = fileUtility.getWorkingDirectory(myName);
+        /* Establish the deployment directory. */
+        deploymentDirectoryFile = new File(fileUtility.getProfileDirectory(),
+                deploymentDirectory);
+        /* Read the maximal policy file if there is one. */
+        /* Read the configuration file for minimal codebase and
+         discovery options.
+         */
+        /* Go through the deployment directory looking for services to deploy.
+         */
+        File[] serviceArchives=
+                deploymentDirectoryFile.listFiles(new ServiceStarterArchiveFileFilter());
+
+        /*
+         Deploy those services.
+         */
+        for (File archiveFile: serviceArchives) {
+            try {
+                deployService(archiveFile);
+            } catch(Throwable t) {
+                log.log(Level.WARNING,
+                        MessageNames.FAILED_DEPLOY_SERVICE,
+                        archiveFile.getPath());
+                log.log(Level.WARNING, MessageNames.EXCEPTION_THROWN, t);
+            }
+        }
+        /* TODO: Establish the interval task to monitor the deployment directory
+        for deployment candidate changes.
+         */
+    }
+
+    private void deployService(File serviceJar) {
+        /* Unpack the jar into working dir. */
+        /* Create the service classloader. */
+        /* Register the service's codebase jars with the codebase service. */
+        /* Setup the classloader's codebase annotation. */
+        /* Grant the appropriate permissions to the service's classloader and
+         protection domain. */
+        /* Setup the liaison configuration. */
+        /* Launch the service. */
+    }
+}

Modified: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Strings.java
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Strings.java?rev=1061342&r1=1061341&r2=1061342&view=diff
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Strings.java (original)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Strings.java Thu Jan 20 15:29:27 2011
@@ -24,16 +24,21 @@ package org.apache.river.container;
 public class Strings {
 
     public static final String
-            COMMAND_LINE_ARGS = "commandLineArgs",
+            ADD_URL="addURL",
+            COMMAND_LINE_ARGS = "commandLineArguments",
             CONFIG_XML = "config.xml",
+            CORE_CONFIG_XML="core-config.xml",
             CONTAINER_JMX_DOMAIN="org.apache.river.container",
             CONTEXT_CLASS = "org.apache.river.container.Context",
             DASH = "-",
             DEFAULT = "default",
             DEFAULT_DISCOVERY_CONTEXT = "defaultDiscoveryContext",
+            DOT_SSAR=".ssar",
             EMPTY = "",
+            INIT_COMPLETE="initComplete",
             NAME="name",
             PROFILE = "profile",
+            PROFILE_DIR="profileDirectory",
             PUT = "put",
             SET = "set",
             TYPE="type",

Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/core-config.xml
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/core-config.xml?rev=1061342&view=auto
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/core-config.xml (added)
+++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/core-config.xml Thu Jan 20 15:29:27 2011
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Document   : config.xml
+    Created on : December 10, 2010, 6:39 PM
+    Author     : trasukg
+    Description:
+        This is the core congifuration that is processed by the
+        Bootstrap system prior to processing the profile's config.xml
+
+        Items defined in this config are subject to being overwritten by the
+        profile's config (e.g. classpath or properties settings).  As such,
+        this is a good place to set defaults.
+
+        It also gives a spot to include elements that are required in every
+        profile, for instance the AnnotatedClassDeployer and MBeanRegistrar.
+-->
+
+<!--
+    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.
+
+ -->
+
+<cfg:container-config  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
+   xmlns:cfg='http://river.apache.org/xml/ns/container/config/1.0'
+   xsi:schemaLocation='http://river.apache.org/xml/ns/container/config/1.0 file:/home/trasukg/development/surrogate/src/schemas/config.xsd'>
+    <cfg:classpath>../../dist/RiverSurrogate.jar</cfg:classpath>
+    <cfg:component class="org.apache.river.container.ShowContextToConsole"/>
+    <cfg:component class="org.apache.river.container.AnnotatedClassDeployer"/>
+
+    <cfg:property name="deploymentDirectory" value="deploy"/>
+
+    <cfg:component class="org.apache.river.container.CommandLineArgumentParser"/>
+    <cfg:component class="org.apache.river.container.MBeanRegistrar"/>
+    <cfg:component class="org.apache.river.container.ShutdownListener"/>
+    <cfg:component class="org.apache.river.container.FileUtilityImpl"
+        name="fileUtility"/>
+    <cfg:component class="org.apache.river.container.ProfileConfigReader"/>
+
+</cfg:container-config>

Modified: incubator/river/jtsk/skunk/surrogate/src/schemas/config.xsd
URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/schemas/config.xsd?rev=1061342&r1=1061341&r2=1061342&view=diff
==============================================================================
--- incubator/river/jtsk/skunk/surrogate/src/schemas/config.xsd (original)
+++ incubator/river/jtsk/skunk/surrogate/src/schemas/config.xsd Thu Jan 20 15:29:27 2011
@@ -13,7 +13,7 @@
                     <xsd:annotation>
                         <xsd:appinfo>
                             <jaxb:property name="elements"/>
-                       </xsd:appinfo>
+                        </xsd:appinfo>
                     </xsd:annotation>
                     <xsd:element ref="tns:property"/>
                     <xsd:element ref="tns:component"/>
@@ -35,7 +35,9 @@
         <xsd:attribute name="name" type="xsd:string" use="optional"/>
     </xsd:complexType>
     
-    <xsd:element name="classpath" type="xsd:string"/>
+    <xsd:element name="classpath" type="xsd:string" minOccurs="0"/>
+
+    <xsd:element name="codebase" type="xsd:string" minOccurs="0"/>
 
     <xsd:element name="property">
         <xsd:complexType>
@@ -51,4 +53,27 @@
         </xsd:complexType>
     </xsd:element>
 
+    <xsd:element name="service-starter-config">
+        <xsd:annotation>
+            <xsd:documentation>
+                This element is used in the configuration file for the
+                service-starter service deployer component.
+            </xsd:documentation>
+        </xsd:annotation>
+        <xsd:complexType>
+            <xsd:sequence>
+                <xsd:element ref="tns:classpath"/>
+                <xsd:element ref="tns:codebase"/>
+                <xsd:choice maxOccurs="unbounded">
+                    <xsd:annotation>
+                        <xsd:appinfo>
+                            <jaxb:property name="elements"/>
+                        </xsd:appinfo>
+                    </xsd:annotation>
+                    <xsd:element name="discovery-context"
+                    type="tns:DiscoveryContextType"/>
+                </xsd:choice>
+            </xsd:sequence>
+        </xsd:complexType>
+    </xsd:element>
 </xsd:schema>