river-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Peter Firmstone <j...@zeus.net.au>
Subject Re: svn commit: r1032867 [2/2] - in /incubator/river/jtsk/skunk/surrogate: ./ nbproject/ nbproject/private/ refdocs/ src/ src/net/ src/net/jini/ src/net/jini/surrogate/ src/org/ src/org/apache/ src/org/apache/river/ src/org/apache/river/container/ src/org/...
Date Tue, 09 Nov 2010 07:14:07 GMT
Sweet use of GuardObject, don't see it used often, but this is certainly 
a good example with reduced coupling.

Cheers,

Peter.


gtrasuk@apache.org wrote:
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/AttributeStoreImpl.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/AttributeStoreImpl.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/AttributeStoreImpl.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/AttributeStoreImpl.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,50 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container;
> +
> +import java.security.GuardedObject;
> +import java.util.HashMap;
> +import java.util.Map;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +public class AttributeStoreImpl implements AttributeStore {
> +
> +    private Map<String, Object> attributes=new HashMap<String, Object>();
> +
> +    /**
> +     Retrieve an attribute, checking security permissions if it happens
> +     to be a guarded object.
> +     @param name
> +     @return
> +     */
> +    public Object getAttribute(String name) {
> +        Object attr=attributes.get(name);
> +        if (attr instanceof GuardedObject) {
> +            return ((GuardedObject) attr).getObject();
> +        }
> +        return attr;
> +    }
> +
> +    public void setAttribute(String name, Object attribute) {
> +        attributes.put(name, attribute);
> +    }
> +
> +}
>
> Added: 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=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Host.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Host.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,65 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +package org.apache.river.container;
> +
> +import java.io.File;
> +import java.util.ArrayList;
> +import java.util.List;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +public class Host {
> +
> +    List<ApplicationEnvironment> applications = new ArrayList();
> +
> +    AttributeStore attributeStore=new AttributeStoreImpl();
> +
> +    public AttributeStore getAttributeStore() {
> +        return attributeStore;
> +    }
> +
> +    public List<ApplicationEnvironment> getApplications() {
> +        return applications;
> +    }
> +
> +    File newWorkDirectory() {
> +        throw new UnsupportedOperationException("Not yet implemented");
> +    }
> +
> +    /**
> +     Create a new application environment and add it to the applications
> +     list in the Host.
> +     @return The newly-created ApplicationEnvironment.
> +     */
> +    public ApplicationEnvironment newApplicationEnvironment() {
> +        ApplicationEnvironment appEnv=new ApplicationEnvironment();
> +        applications.add(appEnv);
> +        return appEnv;
> +    }
> +
> +    /**
> +     Looks up an attribute in the attribute set.
> +     @param name
> +     @return
> +     */
> +    public Object getAttribute(String name) {
> +        return getAttributeStore().getAttribute(name);
> +    }
> +
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/JarFilter.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/JarFilter.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/JarFilter.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/JarFilter.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,42 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +package org.apache.river.container;
> +
> +import java.io.File;
> +import java.io.FileFilter;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +public class JarFilter implements FileFilter {
> +
> +    public boolean accept(File file) {
> +        if (!file.isFile()) {
> +            return false;
> +        }
> +        if (!file.canRead()) {
> +            return false;
> +        }
> +        String name = file.getName();
> +        if (!name.endsWith(".jar")) {
> +            return false;
> +        }
> +        return true;
> +    }
> +}
> +
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Names.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Names.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Names.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/Names.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,26 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container;
> +
> +/**
> + This class holds the names of various things that are used in the container.
> + * @author trasukg
> + */
> +public class Names {
> +    public static final String SURROGATE_INSTALLER="surrogateInstaller";
> +}
>
> Added: 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=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/SettableCodebaseClassLoader.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/SettableCodebaseClassLoader.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,151 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +package org.apache.river.container;
> +
> +import java.io.File;
> +import java.io.IOException;
> +import java.net.MalformedURLException;
> +import java.net.URL;
> +import java.net.URLClassLoader;
> +import java.util.ArrayList;
> +import java.util.List;
> +
> +/**
> + * Extends URLClassLoader to allow alteration of the codebase annotation that
> + * will be extracted from the class loader.  Essentially, allows you to use
> + * one source for the actual classpath, and then have a marshalled object
> + * return an arbitrary codebase.
> + * @author trasukg
> + */
> +public class SettableCodebaseClassLoader extends URLClassLoader {
> +
> +    /** Stores the codebase that will be returned as the codebase annotation.
> +     *
> +     */
> +    private URL codebaseURLs[] = new URL[0];
> +
> +    /**
> +     * Construct using a list of urls and the parent classloader.
> +     * @param urlList A list of URLs (which may point to directories or
> +     * jar files) to form the classpath.
> +     * @param extensionClassloader Class loader to use as parent of this
> +     * class loader.
> +     */
> +    SettableCodebaseClassLoader(URL urlList[], ClassLoader extensionClassloader) {
> +        super(urlList, extensionClassloader);
> +    }
> +
> +    /**
> +     * Get the list of URLs that are used for the codebase annotation.
> +     * Note that this list is not the actual classpath (that is in the
> +     * superclass).  The codebase URLs are imposed to match whatever the Jini
> +     * service wants to expose as its codebase annotation.
> +     * @return
> +     */
> +    @Override
> +    public URL[] getURLs() {
> +        return codebaseURLs;
> +    }
> +
> +    /** Add a URL to this classpath.
> +     */
> +    @Override
> +    protected void addURL(URL url) {
> +        URL[] currentURLS = super.getURLs();
> +        for (int i = 0; i < currentURLS.length; i++) {
> +            if (url.equals(currentURLS[i])) {
> +                return;
> +            }
> +        }
> +        super.addURL(url);
> +    }
> +
> +    /**
> +     * Set the codebase URLs to an arbitrary list of URLs.  These URLs form the
> +     * codebase annotation for classes loaded through this classloader.
> +     * For the sake of general paranoia, sets the codebase to a copy of the
> +     * provided array.
> +     * @param codebase
> +     */
> +    public void setCodebase(URL[] codebase) {
> +        if (codebase == null || codebase.length==0) {
> +            codebaseURLs = new URL[]{};
> +            return;
> +        }
> +
> +        codebaseURLs = new URL[codebase.length];
> +        System.arraycopy(codebase, 0, codebaseURLs, 0, codebase.length);
> +
> +    }
> +
> +    static SettableCodebaseClassLoader createLoader(ClassLoader parent,
> +            File commonDirectory)
> +            throws MalformedURLException, IOException {
> +        List urlList = new ArrayList();
> +
> +        if (!commonDirectory.isDirectory()) {
> +            /* There's no common directory, so we'll just use an empty url list
> +            to create the classloader.
> +             */
> +        } else {
> +            /* Create based around the unpacked directory.
> +             * TODO: Maybe later;  seems to me this would make a decent idea,
> +             * but the Surrogate spec specifically disallows the use of the
> +             * codebase attribute, and seems to require that all classes be
> +             * in the root of the surrogate package jar file.
> +
> +
> +            urlList.add(commonDirectory.toURI().toURL());
> +
> +            /* Add all jar files in the directory. * /
> +            FileFilter filter = new JarFilter();
> +            File[] jars = commonDirectory.listFiles(filter);
> +            for (int i = 0; i < jars.length; i++) {
> +                urlList.add(jars[i].toURI().toURL());
> +            }
> +            */
> +
> +        }
> +        URL[] urlArray = new URL[urlList.size()];
> +        for (int i = 0; i < urlArray.length; i++) {
> +            urlArray[i] = (URL) urlList.get(i);
> +        }
> +        SettableCodebaseClassLoader loader = null;
> +
> +        loader = new SettableCodebaseClassLoader(urlArray, parent);
> +        return loader;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        StringBuffer listString = new StringBuffer();
> +        listString.append(getClass().getName() + " [");
> +        URL[] urlArray = super.getURLs();
> +        for (int i = 0; i < urlArray.length; i++) {
> +            listString.append(" ");
> +            listString.append(urlArray[i]);
> +        }
> +        listString.append("], codebase [");
> +        urlArray = getURLs();
> +        for (int i = 0; i < urlArray.length; i++) {
> +            listString.append(" ");
> +            listString.append(urlArray[i]);
> +        }
> +        listString.append("]");
> +        return listString.toString();
> +    }
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/SurrogateInstaller.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/SurrogateInstaller.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/SurrogateInstaller.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/SurrogateInstaller.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,94 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container;
> +
> +import java.io.File;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +public class SurrogateInstaller {
> +    /**
> +     Create and install a surrogate based on a surrogate file which has
> +     been unpacked into a working directory.
> +
> +     <p>This seems to be a lot like installing a generic application, apart
> +     from the specific ways of determining the surrogate's class, so
> +     one wonders whether we might eventually make this a plain application
> +     loader, and separate out the surrogate-specific items into the
> +     connector.
> +     </p>
> +     <p>More formally then, the surrogate connector could read a surrogate
> +     file, then create a plain application that represents the surrogate.
> +     </p>
> +     <p>In that case, the surrogate application is simply a plain application
> +     that has some extra limitations placed on it (e.g. no access to
> +     local resources, a more restrictive security policy, etc).
> +     </p>
> +
> +     @param workingDir
> +     */
> +    void installSurrogate(Host host, File workingDir) {
> +        // Create a context for the surrogate.
> +        ApplicationEnvironment appEnv = host.newApplicationEnvironment();
> +
> +        try {
> +            /* Configure the application environment. */
> +            configureApplicationEnvironment(appEnv, workingDir);
> +
> +            /* Startup the application environment. */
> +            // Initialize the class loader with the surrogate's classes
> +            /* TODO: Set the parent classloader to what? */
> +            SettableCodebaseClassLoader classLoader =
> +                    SettableCodebaseClassLoader.createLoader(null, workingDir);
> +            appEnv.setClassLoader(classLoader);
> +
> +            // Instantiate the surrogate.
> +            // Try the surrogate's getCodebase method to find the codebase
> +            /*
> +             If codebase method returns nothing,
> +             read the manifest to get the
> +             codebase entries.
> +             */
> +            /*
> +             * Setup the discovery manager for the surrogate.
> +             */
> +            /*
> +             * Publish the surrogate's codebase jars through hosts's codebase server.
> +             */
> +            /* Initialize the surrogate.
> +             */
> +            /*
> +             * In case of failure, unpublish the codebase and clean up.
> +             */
> +            /*
> +             * Initiate liveness callbacks.
> +             */
> +        } catch (Exception e) {
> +            /* TODO: Handle this properly! */
> +            e.printStackTrace();
> +        }
> +        throw new UnsupportedOperationException("Not yet implemented");
> +    }
> +
> +    private void configureApplicationEnvironment(ApplicationEnvironment appEnv, File workingDir) {
> +            /* Read the manifest to get the surrogate's class. */
> +    }
> +
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/ClassInfo.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/ClassInfo.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/ClassInfo.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/ClassInfo.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,73 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container.hsm;
> +
> +import java.lang.reflect.Method;
> +import java.util.HashMap;
> +import java.util.Map;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +class ClassInfo {
> +    Class targetClass=null;
> +
> +    SubstateInfo substateInfo[]=null;
> +
> +    Evaluator transitionEvaluator=null;
> +    ListEvaluator onEntryEvaluator=new ListEvaluator();
> +    ListEvaluator onExitEvaluator=new ListEvaluator();
> +    
> +    public Class getTargetClass() {
> +        return targetClass;
> +    }
> +
> +    public void setTargetClass(Class targetClass) {
> +        this.targetClass = targetClass;
> +    }
> +    
> +    Map<Method, Evaluator> methodMap=new HashMap<Method, Evaluator>();
> +
> +    public Object getInstance() {
> +        return instance;
> +    }
> +
> +    public void setInstance(Object instance) {
> +        this.instance = instance;
> +    }
> +
> +    public Map<Method, Evaluator> getMethodMap() {
> +        return methodMap;
> +    }
> +
> +    public void setMethodMap(Map<Method, Evaluator> methodMap) {
> +        this.methodMap = methodMap;
> +    }
> +    Object instance=null;
> +
> +    public SubstateInfo[] getSubstateInfo() {
> +        return substateInfo;
> +    }
> +
> +    public void setSubstateInfo(SubstateInfo[] substateInfo) {
> +        this.substateInfo = substateInfo;
> +    }
> +
> +
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/Controller.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/Controller.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/Controller.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/Controller.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,35 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container.hsm;
> +
> +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;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +@Documented
> +@Retention(RetentionPolicy.RUNTIME)
> +@Target(ElementType.FIELD)
> +public @interface Controller {
> +
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/Evaluator.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/Evaluator.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/Evaluator.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/Evaluator.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,33 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container.hsm;
> +
> +/**
> + Interface for an object that evaluates "something" against a set of arguments.
> + * @author trasukg
> + */
> +interface Evaluator {
> +
> +    /**
> +     Run the evaluator agains a set of arguments.
> +     @param args
> +     @return
> +     */
> +    void eval(Object[] args);
> +
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/Initial.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/Initial.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/Initial.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/Initial.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,39 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container.hsm;
> +
> +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 to indicate the initial value of a field annotated with @State.
> + * @author trasukg
> + */
> +@Documented
> +@Retention(RetentionPolicy.RUNTIME)
> +@Target(ElementType.FIELD)
> +public @interface Initial {
> +    /**
> +     The initial state value to be assigned to the state upon machine setup.
> +     @return
> +     */
> +    Class value();
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/InvokeEvaluator.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/InvokeEvaluator.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/InvokeEvaluator.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/InvokeEvaluator.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,57 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +package org.apache.river.container.hsm;
> +
> +import java.lang.reflect.Method;
> +import java.util.logging.Level;
> +import java.util.logging.Logger;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +class InvokeEvaluator implements Evaluator {
> +
> +    private static final Logger log = Logger.getLogger(InvokeEvaluator.class.getName());
> +    Object instance;
> +    StateMachineImpl machine;
> +    Method targetMethod;
> +
> +    public InvokeEvaluator(StateMachineImpl machine,
> +            Object instance, Method targetMethod) {
> +        this.machine = machine;
> +        this.instance = instance;
> +        this.targetMethod = targetMethod;
> +    }
> +
> +    public void eval(Object[] args) {
> +        try {
> +            if (log.isLoggable(Level.FINER)) {
> +                log.log(Level.FINER, "Applying event {0} to state {1}",
> +                        new Object[]{targetMethod.getName(),
> +                            instance.getClass().getSimpleName()});
> +            }
> +            machine.output = targetMethod.invoke(instance, args);
> +        } catch (Exception ex) {
> +            log.log(Level.SEVERE, "Applying event {0} to state {1} instance {2}",
> +                    new Object[]{targetMethod.getName(),
> +                        instance.getClass().getSimpleName(), instance});
> +            log.log(Level.SEVERE,
> +                    "Error invoking target method on state instance", ex);
> +        }
> +    }
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/InvokeVoidEvaluator.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/InvokeVoidEvaluator.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/InvokeVoidEvaluator.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/InvokeVoidEvaluator.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,50 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container.hsm;
> +
> +import java.lang.reflect.Method;
> +import java.util.logging.Level;
> +import java.util.logging.Logger;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +class InvokeVoidEvaluator implements Evaluator {
> +    private static final Logger log=Logger.getLogger(InvokeVoidEvaluator.class.getName());
> +
> +    Object instance;
> +    StateMachineImpl machine;
> +    Method targetMethod;
> +
> +    public InvokeVoidEvaluator(StateMachineImpl machine, 
> +            Object instance, Method targetMethod) {
> +        this.machine=machine;
> +        this.instance=instance;
> +        this.targetMethod=targetMethod;
> +    }
> +
> +    public void eval(Object[] args) {
> +        try {
> +            targetMethod.invoke(instance, args);
> +        } catch(Exception ex) {
> +            log.log(Level.SEVERE, "Error invoking target method on state instance", ex);
> +        }
> +    }
> +
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/ListEvaluator.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/ListEvaluator.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/ListEvaluator.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/ListEvaluator.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,51 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container.hsm;
> +
> +import java.util.ArrayList;
> +import java.util.List;
> +
> +/**
> + This would be the core of the proverbial poorly-document, unfinished
> + implementation of Lisp.
> + * @author trasukg
> + */
> +class ListEvaluator implements Evaluator {
> +    private List<Evaluator> evaluators=new ArrayList<Evaluator>();
> +
> +    ListEvaluator(List<Evaluator> list) {
> +        this.evaluators=list;
> +    }
> +
> +    /**
> +     Constructs a list evaluator with an empty list, hence a no-op evaluator.
> +     */
> +    ListEvaluator() {
> +
> +    }
> +
> +    public void add(Evaluator eval) {
> +        evaluators.add(eval);
> +    }
> +
> +    public void eval(Object[] args) {
> +        for (Evaluator e:evaluators) {
> +            e.eval(args);
> +        }
> +    }
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/NopEvaluator.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/NopEvaluator.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/NopEvaluator.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/NopEvaluator.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,33 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container.hsm;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +class NopEvaluator implements Evaluator {
> +
> +    public NopEvaluator() {
> +    }
> +
> +    public void eval(Object[] args) {
> +        return;
> +    }
> +
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/OnEntry.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/OnEntry.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/OnEntry.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/OnEntry.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,38 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container.hsm;
> +
> +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;
> +
> +/**
> + Indicates that the annotated method should be invoked whenever the state is
> + entered.  There is no guarantee on the order of execution of @OnEntry methods,
> + only that the exit methods are invoked before the entry methods for the next
> + state.
> + * @author trasukg
> + */
> +@Documented
> +@Retention(RetentionPolicy.RUNTIME)
> +@Target(ElementType.METHOD)
> +public @interface OnEntry {
> +
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/OnExit.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/OnExit.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/OnExit.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/OnExit.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,38 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container.hsm;
> +
> +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;
> +
> +/**
> + Indicates that the annotated method should be invoked whenever the state is
> + exited.  There is no guarantee on the order of execution of @OnExit methods,
> + only that the exit methods are invoked before the entry methods for the next
> + state.
> + * @author trasukg
> + */
> +@Documented
> +@Retention(RetentionPolicy.RUNTIME)
> +@Target(ElementType.METHOD)
> +public @interface OnExit {
> +
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/Retained.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/Retained.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/Retained.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/Retained.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,36 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container.hsm;
> +
> +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 that indicates a state should be retained across transitions,
> + rather than reset every time the parent state is entered.
> + * @author trasukg
> + */
> +@Documented
> +@Retention(RetentionPolicy.RUNTIME)
> +@Target(ElementType.FIELD)
> +public @interface Retained {
> +
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/RootState.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/RootState.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/RootState.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/RootState.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,36 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container.hsm;
> +
> +import java.lang.annotation.Documented;
> +import java.lang.annotation.Retention;
> +import java.lang.annotation.RetentionPolicy;
> +
> +/**
> + * Annotation to indicate the root class of a hierarchical state machine.
> + * @author trasukg
> + */
> +@Documented
> +@Retention(RetentionPolicy.RUNTIME)
> +public @interface RootState {
> +    /**
> +     The event interface that this machine is intended to implement.
> +     @return
> +     */
> +    Class value();
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/SetFieldEvaluator.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/SetFieldEvaluator.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/SetFieldEvaluator.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/SetFieldEvaluator.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,49 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container.hsm;
> +
> +import java.lang.reflect.Field;
> +import java.util.logging.Level;
> +import java.util.logging.Logger;
> +
> +/**
> + Evaluator that sets the field to a given value.
> + * @author trasukg
> + */
> +class SetFieldEvaluator implements Evaluator {
> +    Field field;
> +    Object targetInstance;
> +    Object value;
> +
> +    public SetFieldEvaluator(Field field, Object targetInstance, Object value) {
> +        this.field=field;
> +        this.targetInstance=targetInstance;
> +        this.value=value;
> +    }
> +
> +    public void eval(Object[] args) {
> +        try {
> +            field.set(targetInstance, value);
> +        } catch (IllegalArgumentException ex) {
> +            Logger.getLogger(SetFieldEvaluator.class.getName()).log(Level.SEVERE, null, ex);
> +        } catch (IllegalAccessException ex) {
> +            Logger.getLogger(SetFieldEvaluator.class.getName()).log(Level.SEVERE, null, ex);
> +        }
> +    }
> +
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/State.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/State.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/State.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/State.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,42 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container.hsm;
> +
> +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 type to indicate a variable that stores a state in a
> + hierarchical state machine.  To specify parallel state (AND-States as per
> + Harel), simply include more than one field marked with @State.
> + * @author trasukg
> + */
> +@Documented
> +@Retention(RetentionPolicy.RUNTIME)
> +@Target(ElementType.FIELD)
> +public @interface State {
> +    /**
> +     An array of state classes that reflect the allowable states for this
> +     state variable.
> +     @return
> +     */
> +    Class[] value();
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateEventEvaluator.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateEventEvaluator.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateEventEvaluator.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateEventEvaluator.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,62 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container.hsm;
> +
> +import java.lang.reflect.Field;
> +import java.lang.reflect.Method;
> +import java.util.Map;
> +import java.util.logging.Level;
> +import java.util.logging.Logger;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +class StateEventEvaluator implements Evaluator {
> +    private static final Logger log=
> +            Logger.getLogger(StateEventEvaluator.class.getName());
> +
> +    Map<Class, ClassInfo> classTable=null;
> +    Field stateField=null;
> +    Object parentState=null;
> +    Method eventMethod=null;
> +
> +    StateEventEvaluator(StateMachineImpl machine, ClassInfo classInfo,
> +            SubstateInfo ssi, Method eventMethod, Object parentState) {
> +        classTable=machine.classTable;
> +        stateField=ssi.getField();
> +        this.parentState=parentState;
> +        this.eventMethod=eventMethod;
> +    }
> +
> +    public void eval(Object[] args) {
> +        try {
> +        // Look up the state instance.
> +        Object state=stateField.get(parentState);
> +        // From the class, find its event table
> +        ClassInfo ci=classTable.get(state.getClass());
> +        // Lookup the correct evaluator for this event
> +        Evaluator eval=ci.methodMap.get(eventMethod);
> +        // Execute it.
> +        eval.eval(args);
> +        } catch (Exception e) {
> +            log.log(Level.SEVERE, "Error invoking target method on state instance", e);
> +        }
> +    }
> +
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateMachine.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateMachine.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateMachine.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateMachine.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,31 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container.hsm;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +public interface StateMachine {
> +    /**
> +     Initiate a transition to the target state.
> +     @param targetState
> +     */
> +    public void transition(Class targetState);
> +    
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateMachineFactory.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateMachineFactory.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateMachineFactory.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateMachineFactory.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,70 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +package org.apache.river.container.hsm;
> +
> +import java.lang.reflect.InvocationHandler;
> +import java.lang.reflect.InvocationTargetException;
> +import java.lang.reflect.Method;
> +import java.lang.reflect.Proxy;
> +import java.util.HashMap;
> +import java.util.Map;
> +import java.util.concurrent.Callable;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +class StateMachineFactory {
> +
> +    /**
> +    <p>
> +    Create a state machine instance based on the supplied class.
> +    </p>
> +
> +    <p>
> +    The class must be annotated with the @HSMRoot annotation and supplied
> +    event interface.
> +    </p>
> +
> +    <p>
> +    The proxy created implements the event interface, but instantiates
> +    a hierarchical state machine that executes the interface starting with
> +    the state given.
> +    </p>
> +    @param aClass A class annotated with @HSMRoot.
> +    @return
> +     */
> +    static Object createStateMachine(Class aClass) throws InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
> +        // Create a dynamic proxy for the given class.
> +
> +        /* Check the annotation to find out the event interface.
> +         */
> +        RootState ann = (RootState) aClass.getAnnotation(RootState.class);
> +        Class eventInterface = ann.value();
> +        Object rootState = aClass.newInstance();
> +        StateMachineImpl machine=new StateMachineImpl();
> +        machine.initializeEventTable(aClass, eventInterface);
> +        machine.rootState=rootState;
> +        machine.updateActiveStatesAndRunEntryMethods();
> +        Object proxy =
> +                Proxy.newProxyInstance(eventInterface.getClassLoader(),
> +                new Class[]{eventInterface},
> +                machine);
> +        return proxy;
> +    }
> +
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateMachineImpl.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateMachineImpl.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateMachineImpl.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateMachineImpl.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,309 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +package org.apache.river.container.hsm;
> +
> +import java.lang.reflect.Constructor;
> +import java.lang.reflect.Field;
> +import java.lang.reflect.InvocationHandler;
> +import java.lang.reflect.InvocationTargetException;
> +import java.lang.reflect.Method;
> +import java.util.ArrayList;
> +import java.util.HashMap;
> +import java.util.List;
> +import java.util.Map;
> +import org.apache.river.container.hsm.Controller;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +class StateMachineImpl implements StateMachine, InvocationHandler {
> +
> +    Object rootState;
> +    Object output = null;
> +    List<Class> transitions = new ArrayList<Class>(20);
> +    Map<Class, ClassInfo> classTable =
> +            new HashMap<Class, ClassInfo>();
> +    List<Class> activeStates = new ArrayList<Class>(50);
> +
> +    public StateMachineImpl() {
> +    }
> +
> +    public void transition(Class targetState) {
> +        transitions.add(targetState);
> +    }
> +
> +    /**
> +    Initialize the event table for a class, given an event interface.
> +    @param aClass
> +    @param eventInterface
> +     */
> +    void initializeEventTable(Class aClass, Class eventInterface) throws InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
> +        // Create the class info entry
> +        ClassInfo classInfo = new ClassInfo();
> +        // Store the class info in the overall table.
> +        classTable.put(aClass, classInfo);
> +
> +        classInfo.setTargetClass(aClass);
> +
> +        // Create the instance for this class.
> +        classInfo.setInstance(createInstance(aClass));
> +
> +        /* Populate the substates, then initialize event table for all the
> +        possible substates. */
> +        populateClassInfo(classInfo);
> +        processSubstates(classInfo, eventInterface);
> +        buildMethodMap(eventInterface, classInfo);
> +    }
> +
> +    private void buildMethodMap(Class eventInterface, ClassInfo classInfo) throws SecurityException {
> +        for (Method m : eventInterface.getMethods()) {
> +            /*
> +            If there are substates, then the evaluator has to run the
> +            event on each substate, then run our event handler.
> +             */
> +            List<Evaluator> evaluators = new ArrayList<Evaluator>();
> +            for (SubstateInfo ssi : classInfo.getSubstateInfo()) {
> +                evaluators.add(new StateEventEvaluator(this, classInfo, ssi, m, classInfo.getInstance()));
> +            }
> +            evaluators.add(createEvaluator(classInfo, m));
> +            classInfo.getMethodMap().put(m, new ListEvaluator(evaluators));
> +        }
> +    }
> +
> +    private void processSubstates(ClassInfo classInfo, Class eventInterface) throws IllegalAccessException, InvocationTargetException, IllegalArgumentException, NoSuchMethodException, InstantiationException {
> +        for (SubstateInfo ssi : classInfo.getSubstateInfo()) {
> +            for (Class c : ssi.getPossibleStates()) {
> +                initializeEventTable(c, eventInterface);
> +                ClassInfo substateInfo = classTable.get(c);
> +                substateInfo.transitionEvaluator =
> +                        new SetFieldEvaluator(ssi.getField(), classInfo.getInstance(),
> +                        substateInfo.getInstance());
> +            }
> +            setupInitialState(ssi, classInfo);
> +
> +        }
> +    }
> +
> +    private void setupInitialState(SubstateInfo ssi, ClassInfo classInfo) throws IllegalAccessException, IllegalArgumentException {
> +        Object initialInstance = classTable.get(ssi.getInitialState()).getInstance();
> +        ssi.getField().set(classInfo.getInstance(), initialInstance);
> +        /* If the state isn't supposed to be retained, add state setter to
> +        entryEvaluator. */
> +        if (!ssi.isRetained()) {
> +            classInfo.onEntryEvaluator.add(new SetFieldEvaluator(ssi.getField(),
> +                    classInfo.instance, initialInstance));
> +        }
> +    }
> +
> +    public synchronized Object invoke(Object proxy, Method method, Object[] args)
> +            throws Throwable {
> +        /* Lookup evaluator for this event on the root state's class */
> +        Evaluator evaluator =
> +                classTable.get(rootState.getClass()).getMethodMap().get(method);
> +
> +        /* Run that evaluator, which will have been created with knowledge
> +        of the output register. */
> +        output = null;
> +        transitions.clear();
> +        evaluator.eval(args);
> +        applyTransitions();
> +        return output;
> +    }
> +
> +    /**
> +    Apply the transitions that were accumulated during the event run.
> +     */
> +    private void applyTransitions() throws IllegalArgumentException, IllegalAccessException {
> +        while (!transitions.isEmpty()) {
> +            /* For each transition, Set the state variable.
> +             */
> +            for (Class toClass : transitions) {
> +                ClassInfo ci = classTable.get(toClass);
> +                ci.transitionEvaluator.eval(null);
> +            }
> +            transitions.clear();
> +            updateActiveStatesAndRunEntryMethods();
> +        }
> +    }
> +
> +    void updateActiveStatesAndRunEntryMethods() throws IllegalAccessException, IllegalArgumentException {
> +        // Calculate the new state vector.
> +        List<Class> newStates = getActiveStates();
> +        // Generate exiting and entering states from the state vector.
> +        List<Class> exitingStates = new ArrayList<Class>();
> +        List<Class> enteringStates = new ArrayList<Class>();
> +        for (Class c : activeStates) {
> +            if (!newStates.contains(c)) {
> +                exitingStates.add(c);
> +            }
> +        }
> +        for (Class c : newStates) {
> +            if (!activeStates.contains(c)) {
> +                enteringStates.add(c);
> +            }
> +        }
> +        // Apply exit methods.
> +        for (Class c : exitingStates) {
> +            ClassInfo ci = classTable.get(c);
> +            ci.onExitEvaluator.eval(null);
> +        }
> +        // Apply entry methods.
> +        for (Class c : enteringStates) {
> +            ClassInfo ci = classTable.get(c);
> +            ci.onEntryEvaluator.eval(null);
> +        }
> +        // Update the current state vector.
> +        activeStates = newStates;
> +    }
> +
> +    public List<Class> getActiveStates() throws IllegalArgumentException, IllegalAccessException {
> +        List<Class> ret = new ArrayList<Class>(50);
> +        // Start at the root class
> +        ClassInfo start = classTable.get(rootState.getClass());
> +        getActiveStates(ret, start);
> +        // For each substate,
> +        // Add the substate
> +        //
> +        return ret;
> +    }
> +
> +    private void getActiveStates(List<Class> list, ClassInfo ci) throws IllegalArgumentException, IllegalAccessException {
> +        list.add(ci.getTargetClass());
> +        for (SubstateInfo ssi : ci.getSubstateInfo()) {
> +            Object instance = ssi.getField().get(ci.getInstance());
> +            getActiveStates(list, classTable.get(instance.getClass()));
> +        }
> +    }
> +
> +    /**
> +    Create the evaluator that runs the method on the class pointed to by
> +    classInfo.
> +    @param classInfo
> +    @param m
> +    @return
> +     */
> +    private Evaluator createEvaluator(ClassInfo classInfo, Method m) {
> +        try {
> +            Method targetMethod =
> +                    classInfo.getTargetClass().getMethod(m.getName(),
> +                    m.getParameterTypes());
> +            if (targetMethod.getReturnType() == null) {
> +                return new InvokeVoidEvaluator(this, classInfo.getInstance(),
> +                        targetMethod);
> +            } else {
> +                return new InvokeEvaluator(this, classInfo.getInstance(),
> +                        targetMethod);
> +            }
> +        } catch (NoSuchMethodException nsme) {
> +            return new NopEvaluator();
> +        }
> +    }
> +
> +    private void populateClassInfo(ClassInfo classInfo) throws IllegalArgumentException, IllegalAccessException {
> +        populateSubstateInfo(classInfo);
> +        handleControllerAnnotation(classInfo);
> +        handleEntryAnnotation(classInfo);
> +        handleExitAnnotation(classInfo);
> +    }
> +
> +    private void populateSubstateInfo(ClassInfo classInfo) {
> +        // Look for fields annotated with @State.
> +        List<SubstateInfo> substateInfo = new ArrayList<SubstateInfo>();
> +        for (Field f : classInfo.getTargetClass().getDeclaredFields()) {
> +            State ann = (State) f.getAnnotation(State.class);
> +            if (ann == null) {
> +                continue;
> +            }
> +            SubstateInfo info = new SubstateInfo();
> +            info.setField(f);
> +            substateInfo.add(info);
> +            if (ann.value() == null) {
> +                throw new RuntimeException("@State needs a list of possible states");
> +            }
> +            info.setPossibleStates(ann.value());
> +            Initial initialAnn = f.getAnnotation(Initial.class);
> +            if (initialAnn == null) {
> +                throw new RuntimeException("Need initial state for "
> +                        + f.getName());
> +            }
> +            info.setInitialState(initialAnn.value());
> +            Retained retainedAnn = f.getAnnotation(Retained.class);
> +            info.setRetained(retainedAnn != null);
> +        }
> +        classInfo.setSubstateInfo(substateInfo.toArray(new SubstateInfo[0]));
> +    }
> +
> +    /**
> +    Create an instance of the a state class, even if it happens to be an
> +    inner class of another state class.
> +    <p>
> +    A frequent pattern is to have the substate classes listed as inner classes
> +    on their enclosing state's class, allowing sharing of attributes.  So we
> +    need to allow an instance to be created, even if the class is not static.
> +    </p>
> +
> +    <p>
> +    The only requirement is that the enclosing class is also a class within
> +    the state machine.
> +    </p>
> +    @param aClass
> +    @return
> +     */
> +    private Object createInstance(Class aClass) throws InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
> +        Class enclosingClass = aClass.getEnclosingClass();
> +        if (enclosingClass == null) {
> +            return aClass.newInstance();
> +        }
> +        ClassInfo enclosingClassInfo = classTable.get(enclosingClass);
> +        Constructor con = aClass.getConstructor(enclosingClass);
> +        return con.newInstance(enclosingClassInfo.getInstance());
> +    }
> +
> +    /**
> +    If the class mentioned has an @Controller annotation, set its reference
> +    to the state machine implementation.
> +    @param classInfo
> +     */
> +    private void handleControllerAnnotation(ClassInfo classInfo) throws IllegalArgumentException, IllegalAccessException {
> +        for (Field f : classInfo.getTargetClass().getDeclaredFields()) {
> +            if (f.getAnnotation(Controller.class) != null) {
> +                f.set(classInfo.getInstance(), this);
> +            }
> +        }
> +    }
> +
> +    private void handleEntryAnnotation(ClassInfo classInfo) {
> +        // If there are any methods flagged @OnEnter, put them into the entry
> +        // evaluator.
> +        for (Method m : classInfo.getTargetClass().getDeclaredMethods()) {
> +            if (m.getAnnotation(OnEntry.class) != null) {
> +                classInfo.onEntryEvaluator.add(new InvokeVoidEvaluator(this, classInfo.instance, m));
> +            }
> +        }
> +    }
> +
> +    private void handleExitAnnotation(ClassInfo classInfo) {
> +        // If there are any methods flagged @OnExit, put them into the entry
> +        // evaluator.
> +        for (Method m : classInfo.getTargetClass().getDeclaredMethods()) {
> +            if (m.getAnnotation(OnExit.class) != null) {
> +                classInfo.onExitEvaluator.add(new InvokeVoidEvaluator(this, classInfo.instance, m));
> +            }
> +        }
> +    }
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateMachineInvocationHandler.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateMachineInvocationHandler.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateMachineInvocationHandler.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/StateMachineInvocationHandler.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,126 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +package org.apache.river.container.hsm;
> +
> +import java.lang.reflect.InvocationHandler;
> +import java.lang.reflect.Method;
> +import java.util.ArrayList;
> +import java.util.HashMap;
> +import java.util.List;
> +import java.util.Map;
> +
> +/**
> + <p>
> + Invocation handler for the state machine proxy.
> + </p>
> +
> + <p>
> + The state machine factory creates one proxy that corresponds to the state
> + machine, and runs "events" (which are represented by method calls) on the
> + state machine.  The actual execution of these method calls may involve
> + calling methods on the individual classes that make up the state machine.
> + </p>
> +
> + <p>
> + Execution will look something like this:
> + <ul>
> + <li>Get the current state</li>
> + <li>Run the event method on all substates of the current state</li>
> + <li>Run the event method on the current state</li>
> + <li>Running the events may have generated transitions, so:
> +    <uL>
> +    <li>Generate the vector of states that are active after the
> +    transitions.</li>
> +    </li>Compare that to the current state vector, generating exit and entry
> +    vectors</li>
> +    <li>Execute exit, then entry actions for the complete vector.</li>
> +    <li>Executing the exit and entry actions may have generated transitions;
> +    repeat the above until there are no transitions to execute.</li>
> +    </ul>
> +  <li>Package the output into an object as return value.</li>
> +  </li>Store the current-states vector</li>
> +  </li>Return.</li>
> +  </ul>
> +
> +
> + </p>
> + * @author trasukg
> + */
> +public class StateMachineInvocationHandler implements InvocationHandler {
> +
> +    Object rootState = null;
> +    Map<Method, InvocationHandler> methodMap = new HashMap<Method, InvocationHandler>();
> +
> +    StateMachineInvocationHandler(Object instance, Class eventInterface) {
> +        this.rootState = instance;
> +        /* For every method in the event interface, create a
> +        callable that will invoke the matching method on the rootState.
> +         */
> +        //initializeMethodMap(eventInterface);
> +    }
> +
> +    private void initializeMethodMap_Old(Class eventInterface) {
> +        for (Method m : eventInterface.getMethods()) {
> +            try {
> +                final Method targetMethod =
> +                        rootState.getClass().getMethod(m.getName(),
> +                        m.getParameterTypes());
> +                final Object finalInstance = rootState;
> +                InvocationHandler targetHandler = new InvocationHandler() {
> +
> +                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
> +                        return targetMethod.invoke(finalInstance, args);
> +                    }
> +                };
> +                methodMap.put(m, targetHandler);
> +            } catch (NoSuchMethodException nsme) {
> +                methodMap.put(m, new InvocationHandler() {
> +
> +                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
> +                        return null;
> +                    }
> +                });
> +            }
> +        }
> +
> +
> +    }
> +    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
> +        /* Create a controller and output value list. */
> +        StateMachine controller = new StateMachineImpl();
> +        List<Object> output = new ArrayList<Object>();
> +
> +        /* Invoke with the controller and output list. */
> +        this.invoke(controller, output, rootState, method, args);
> +        if (output.isEmpty()) {
> +            return null;
> +        }
> +        if (output.size()==1) {
> +            return output.get(0);
> +        }
> +        return output.toArray();
> +    }
> +
> +    private void invoke(StateMachine controller, List<Object> output, Object instance, Method method, Object[] args) throws Throwable {
> +        Object outObj= methodMap.get(method).invoke(instance, method, args);
> +        /*
> +         If the method is expected to return something, then add that something
> +         to the output, even if it was null.
> +         */
> +        output.add(outObj);
> +    }
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/SubstateInfo.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/SubstateInfo.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/SubstateInfo.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/src/org/apache/river/container/hsm/SubstateInfo.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,65 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +package org.apache.river.container.hsm;
> +
> +import java.lang.reflect.Field;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +class SubstateInfo {
> +
> +    private Field field;
> +    private Class[] possibleStates;
> +    private Class initialState;
> +    private boolean retained=false;
> +
> +    public Field getField() {
> +        return field;
> +    }
> +
> +    public void setField(Field field) {
> +        this.field = field;
> +    }
> +
> +    public Class getInitialState() {
> +        return initialState;
> +    }
> +
> +    public void setInitialState(Class initialState) {
> +        this.initialState = initialState;
> +    }
> +
> +    public Class[] getPossibleStates() {
> +        return possibleStates;
> +    }
> +
> +    public void setPossibleStates(Class[] possibleStates) {
> +        this.possibleStates = possibleStates;
> +    }
> +
> +    public boolean isRetained() {
> +        return retained;
> +    }
> +
> +    public void setRetained(boolean retained) {
> +        this.retained = retained;
> +    }
> +
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSM.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSM.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSM.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSM.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,121 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +package org.apache.river.container.hsm;
> +
> +import java.util.List;
> +import java.util.logging.Level;
> +import java.util.logging.Logger;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +@RootState(TestSMInterface.class)
> +public class TestSM {
> +
> +    @State({A.class, B.class})
> +    @Initial(A.class)
> +    @Retained
> +    Object state;
> +    @Controller
> +    StateMachine controller;
> +    int nullTransitionEntryCount = 0;
> +    int aEntryCount = 0, aExitCount = 0;
> +
> +    public List<Class> getActiveStates() {
> +        try {
> +            return ((StateMachineImpl) controller).getActiveStates();
> +        } catch (IllegalArgumentException ex) {
> +            Logger.getLogger(TestSM.class.getName()).log(Level.SEVERE, null, ex);
> +            throw new RuntimeException(ex);
> +        } catch (IllegalAccessException ex) {
> +            Logger.getLogger(TestSM.class.getName()).log(Level.SEVERE, null, ex);
> +            throw new RuntimeException(ex);
> +        }
> +    }
> +
> +    public void gotoA() {
> +        controller.transition(A.class);
> +    }
> +
> +    public void gotoB() {
> +        controller.transition(B.class);
> +    }
> +
> +    public int getAEntryCount() {
> +        return aEntryCount;
> +    }
> +
> +    public int getAExitCount() {
> +        return aExitCount;
> +    }
> +
> +    public int getNullTransitionEntryCount() {
> +        return nullTransitionEntryCount;
> +    }
> +
> +    public String sayConstantHello() {
> +        return "Hello";
> +    }
> +
> +    public class A {
> +
> +        public String sayHello() {
> +            controller.transition(B.class);
> +            return "Hello";
> +        }
> +
> +        public void nullTransition() {
> +            controller.transition(A.class);
> +        }
> +
> +        @OnEntry
> +        public void onEntry() {
> +            aEntryCount++;
> +            nullTransitionEntryCount++;
> +        }
> +
> +        @OnExit
> +        public void onExit() {
> +            aExitCount++;
> +        }
> +    }
> +
> +    public class B {
> +
> +        @State({B1.class, B2.class, B3.class})
> +        @Initial(B1.class)
> +        Object state;
> +
> +        public String sayHello() {
> +            return "There";
> +        }
> +    }
> +
> +    public class B1 {
> +
> +        public void moveSubstateOfB() {
> +            controller.transition(B2.class);
> +        }
> +    }
> +
> +    public class B2 {
> +    }
> +
> +    public class B3 {
> +    }
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSMInterface.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSMInterface.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSMInterface.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSMInterface.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,47 @@
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +package org.apache.river.container.hsm;
> +
> +import java.util.List;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +public interface TestSMInterface {
> +
> +    public String sayHello();
> +
> +    public String sayConstantHello();
> +
> +    public Object returnNull();
> +
> +    public int getNullTransitionEntryCount();
> +
> +    public void nullTransition();
> +
> +    public int getAEntryCount();
> +
> +    public int getAExitCount();
> +
> +    public void moveSubstateOfB();
> +
> +    public void gotoA();
> +    public void gotoB();
> +
> +    List<Class> getActiveStates();
> +}
>
> Added: incubator/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSimpleMachine.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSimpleMachine.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSimpleMachine.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/test/org/apache/river/container/hsm/TestSimpleMachine.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,224 @@
> +package org.apache.river.container.hsm;
> +
> +/*
> + *  Copyright 2010 trasukg.
> + * 
> + *  Licensed 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.
> + *  under the License.
> + */
> +
> +import java.util.List;
> +import java.lang.reflect.InvocationTargetException;
> +import java.util.logging.Logger;
> +import java.lang.reflect.Field;
> +import java.util.logging.Level;
> +import org.junit.After;
> +import org.junit.AfterClass;
> +import org.junit.Before;
> +import org.junit.BeforeClass;
> +import org.junit.Test;
> +import static org.junit.Assert.assertEquals;
> +import static org.junit.Assert.assertFalse;
> +import static org.junit.Assert.assertTrue;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +public class TestSimpleMachine {
> +
> +    public TestSimpleMachine() throws InstantiationException, IllegalAccessException,
> +    NoSuchMethodException, InvocationTargetException {
> +    }
> +
> +    @BeforeClass
> +    public static void setUpClass() throws Exception {
> +        Logger.getLogger("org.apache.river.container.hsm").setLevel(Level.FINER);
> +    }
> +
> +    @AfterClass
> +    public static void tearDownClass() throws Exception {
> +    }
> +
> +    @Before
> +    public void setUp() {
> +    }
> +
> +    @After
> +    public void tearDown() {
> +    }
> +
> +    TestSMInterface UUT=(TestSMInterface)
> +                StateMachineFactory.createStateMachine(TestSM.class);
> +
> +    @Test
> +    /**
> +     Confirm that we understand the use of getAnnotation.
> +     Getting the HSMRoot annotation on TestSM.class should yield
> +     EventInterface.class.
> +     */
> +    public void testRootStateAnnotation() {
> +        RootState ann=(RootState) TestSM.class.getAnnotation(RootState.class);
> +        Class eventInterface=ann.value();
> +        assertEquals(TestSMInterface.class, eventInterface);
> +    }
> +
> +    @Test
> +    /**
> +     Make sure we can read the annotations on the 'state' field.
> +     */
> +    public void testStateAnnotation() throws NoSuchFieldException {
> +        Class testSMClass=TestSM.class;
> +        Field stateField=testSMClass.getDeclaredField("state");
> +        /* Check the State annotation. */
> +        State stateAnn=stateField.getAnnotation(State.class);
> +        assertTrue("No state annotation present.", stateAnn != null);
> +    }
> +
> +    @Test
> +    /** Verify that the list of active states is correct at beginning.
> +
> +     */
> +    public void testActiveStates() {
> +
> +        assertEquals(2, UUT.getActiveStates().size());
> +        assertTrue("activeStates should contain root state.",
> +                UUT.getActiveStates().contains(TestSM.class));
> +        assertTrue("activeStates should contain A.",
> +                UUT.getActiveStates().contains(TestSM.A.class));
> +    }
> +
> +    @Test
> +    /**
> +     Test that the top-level (state-invariant) sayHelloConstant() method returns
> +     the correct value.  Verifies that the top-level proxy is functioning
> +     correctly.
> +     */
> +    public void testStateMachine() throws InstantiationException, IllegalAccessException {
> +        assertEquals("Hello", UUT.sayConstantHello());
> +    }
> +
> +    @Test
> +    /**
> +     Test that the top-level (state-invariant) sayHelloConstant() method returns
> +     the correct value.  Verifies that the top-level proxy is functioning
> +     correctly.
> +     */
> +    public void testNullReturn() throws InstantiationException, IllegalAccessException {
> +        assertEquals(null, UUT.returnNull());
> +    }
> +
> +    @Test
> +    /**
> +     <p>
> +     Verify that transitions from state A to B work, and that the behaviour
> +     varies with state.
> +     </p>
> +
> +     <p>
> +     First call to sayHello() should return "Hello", second call should return
> +     "There".
> +     </p>
> +
> +     */
> +    public void testSimpleTransition() throws InstantiationException, IllegalAccessException {
> +        assertTrue("activeStates should contain A.",
> +                UUT.getActiveStates().contains(TestSM.A.class));
> +        assertEquals("Hello", UUT.sayHello());
> +        assertTrue("activeStates should contain B after transition.",
> +                UUT.getActiveStates().contains(TestSM.B.class));
> +        assertEquals("There", UUT.sayHello());
> +
> +    }
> +
> +    @Test
> +    /**
> +     When we enter a state, the entry method should be called.
> +     */
> +    public void testEntryMethodExecution() {
> +        assertEquals(1, UUT.getAEntryCount());
> +        UUT.sayHello();
> +        assertEquals(1, UUT.getAExitCount());
> +    }
> +
> +    @Test
> +    /**
> +     When we transition to a state but we are already in that state, the
> +     onEntry method should not be run.
> +     */
> +    public void testNullTransition() {
> +        UUT.nullTransition();
> +        UUT.nullTransition();
> +        UUT.nullTransition();
> +        assertEquals(1, UUT.getNullTransitionEntryCount());
> +    }
> +
> +    @Test
> +    /**
> +     Make sure that the gotoA() and gotoB() methods cause the appropriate
> +     transitions.
> +     */
> +    public void testABTransitions() {
> +        UUT.gotoA();
> +        assertTrue("activeStates should contain A.",
> +                UUT.getActiveStates().contains(TestSM.A.class));
> +        assertFalse("activeStates should not contain B.",
> +                 UUT.getActiveStates().contains(TestSM.B.class));
> +        UUT.gotoB();
> +
> +        assertFalse("activeStates should not contain A.",
> +                 UUT.getActiveStates().contains(TestSM.A.class));
> +        assertTrue("activeStates should contain B.",
> +                UUT.getActiveStates().contains(TestSM.B.class));
> +
> +        UUT.gotoA();
> +        assertTrue("activeStates should contain A.",
> +                UUT.getActiveStates().contains(TestSM.A.class));
> +        assertFalse("activeStates should not contain B.",
> +                 UUT.getActiveStates().contains(TestSM.B.class));
> +    }
> +
> +    @Test
> +    /**
> +     @Retained annotations should be respected, and states should be
> +     initialized on entry if the @Retained is not there.
> +     */
> +    public void testStateInitialization() {
> +        UUT.gotoA();
> +        assertTrue("activeStates should contain A.",
> +                UUT.getActiveStates().contains(TestSM.A.class));
> +        assertFalse("activeStates should not contain B.",
> +                 UUT.getActiveStates().contains(TestSM.B.class));
> +        UUT.gotoB();
> +
> +        assertFalse("activeStates should not contain A.",
> +                 UUT.getActiveStates().contains(TestSM.A.class));
> +        assertTrue("activeStates should contain B.",
> +                UUT.getActiveStates().contains(TestSM.B.class));
> +        assertTrue("activeStates should contain B1.",
> +                UUT.getActiveStates().contains(TestSM.B1.class));
> +
> +        UUT.moveSubstateOfB();
> +        assertTrue("activeStates should contain B2.",
> +                UUT.getActiveStates().contains(TestSM.B2.class));
> +        UUT.gotoA();
> +        /* the substate isn't marked @Retained, so should reset to initial
> +         on gotoB().
> +         */
> +        UUT.gotoB();
> +        assertTrue("activeStates should contain B1.",
> +                UUT.getActiveStates().contains(TestSM.B1.class));
> +
> +
> +    }
> +}
> \ No newline at end of file
>
> Added: incubator/river/jtsk/skunk/surrogate/test/org/apache/river/surrogate/SurrogateContextTest.java
> URL: http://svn.apache.org/viewvc/incubator/river/jtsk/skunk/surrogate/test/org/apache/river/surrogate/SurrogateContextTest.java?rev=1032867&view=auto
> ==============================================================================
> --- incubator/river/jtsk/skunk/surrogate/test/org/apache/river/surrogate/SurrogateContextTest.java (added)
> +++ incubator/river/jtsk/skunk/surrogate/test/org/apache/river/surrogate/SurrogateContextTest.java Tue Nov  9 06:32:31 2010
> @@ -0,0 +1,55 @@
> +/*
> + * To change this template, choose Tools | Templates
> + * and open the template in the editor.
> + */
> +
> +package org.apache.river.surrogate;
> +
> +import org.apache.river.container.ApplicationEnvironment;
> +import org.junit.After;
> +import org.junit.AfterClass;
> +import org.junit.Before;
> +import org.junit.BeforeClass;
> +import org.junit.Test;
> +import static org.junit.Assert.*;
> +
> +/**
> + *
> + * @author trasukg
> + */
> +public class SurrogateContextTest {
> +
> +    ApplicationEnvironment UUT=null;
> +
> +    public SurrogateContextTest() {
> +    }
> +
> +    @BeforeClass
> +    public static void setUpClass() throws Exception {
> +    }
> +
> +    @AfterClass
> +    public static void tearDownClass() throws Exception {
> +    }
> +
> +    @Before
> +    public void setUp() {
> +        UUT=new ApplicationEnvironment();
> +    }
> +
> +    @After
> +    public void tearDown() {
> +    }
> +
> +    /**
> +     * We should be able to point the context at a jar file
> +     * and have it unpack the file in preparation for serving the
> +     * surrogate out of that unpacked directory.
> +     */
> +    @Test
> +    public void testJarUnpack() {
> +
> +    }
> +
> +
> +}
> \ No newline at end of file
>
>
>
>   


Mime
View raw message