From ed5da52253e5847aebd4fd8afc0a371eb00e10e1 Mon Sep 17 00:00:00 2001 From: willemc Date: Thu, 27 Jul 2006 14:53:20 +0200 Subject: [PATCH] [svn r115] added the rest of foei --- .classpath | 2 + lib/commons-beanutils.jar | Bin 0 -> 188671 bytes lib/idcanet-x4o-bin.jar | Bin 0 -> 40879 bytes src/META-INF/events.eld | 33 + src/META-INF/filters.eld | 57 ++ src/META-INF/foei-context-defaults.xml | 23 + src/META-INF/foei-namespaces.properties | 18 + src/META-INF/io.eld | 53 ++ src/META-INF/lang.eld | 105 +++ src/META-INF/logging.eld | 35 + src/META-INF/printers.eld | 61 ++ .../foei/components/io/ErrorOutput.java | 72 ++ .../foei/components/io/FileOutput.java | 36 + .../foei/components/io/StandardOutput.java | 73 ++ .../foei/components/logging/Log4jInput.java | 64 ++ .../components/logging/LoggerHandler.java | 65 ++ .../foei/components/logging/LoggerInput.java | 67 ++ .../foei/components/logging/package.html | 55 ++ .../components/steps/filters/ClassFilter.java | 88 +++ .../components/steps/filters/DateFilter.java | 77 ++ .../steps/filters/NumberFilter.java | 116 +++ .../steps/filters/StringFilter.java | 158 +++++ .../components/steps/filters/package.html | 55 ++ .../steps/lang/GetBeanPropertyStep.java | 78 ++ .../foei/components/steps/lang/ListValue.java | 79 +++ .../foei/components/steps/lang/MapValue.java | 88 +++ .../foei/components/steps/lang/package.html | 57 ++ .../steps/printers/DatePrinter.java | 88 +++ .../steps/printers/DefaultPrinter.java | 98 +++ .../components/steps/printers/package.html | 61 ++ .../foei/core/impl/EventExecutorImpl.java | 126 ++++ .../core/impl/EventExecutorManagerImpl.java | 201 ++++++ .../core/impl/EventExecutorThreadFactory.java | 91 +++ .../EventThreadListenersRunnableWrapper.java | 75 ++ .../foei/core/impl/FoeiConfiguratorImpl.java | 264 +++++++ .../foei/core/impl/FoeiContextImpl.java | 149 ++++ .../impl/FoeiEventBindingRuleHandler.java | 88 +++ .../foei/core/impl/FoeiProcessImpl.java | 187 +++++ .../core/impl/FoeiProcessManagerImpl.java | 125 ++++ .../core/impl/FoeiProcessRunnableWrapper.java | 70 ++ .../core/impl/ObjectBindingsManagerImpl.java | 179 +++++ .../foei/core/impl/X2OExecutorImpl.java | 150 ++++ src/com/idcanet/foei/core/impl/package.html | 58 ++ .../foei/core/x4o/BindAttributeHandler.java | 94 +++ .../core/x4o/EventStepBindRuleHandler.java | 76 ++ .../foei/core/x4o/IdAttributeHandler.java | 67 ++ .../foei/core/x4o/ObjectBindingElement.java | 150 ++++ .../foei/core/x4o/SetParameterElement.java | 88 +++ src/com/idcanet/foei/core/x4o/package.html | 55 ++ .../foei/event/annotations/SetEventPort.java | 70 ++ .../foei/event/annotations/SetEventPorts.java | 49 ++ .../foei/server/config/FoeiConfigContext.java | 37 + .../foei/server/config/FoeiConfigParser.java | 70 ++ .../config/FoeiContextXMLTagHandler.java | 65 ++ .../idcanet/foei/server/config/package.html | 69 ++ .../server/startup/FoeiStartupListener.java | 107 +++ .../idcanet/foei/server/startup/package.html | 69 ++ .../foei/utils/beans/BeanProperty.java | 40 ++ .../utils/beans/BeanPropertyComparator.java | 174 +++++ .../foei/utils/beans/NumberComparator.java | 95 +++ src/com/idcanet/foei/utils/beans/package.html | 61 ++ .../foei/utils/jdbc/ConnectionFactory.java | 56 ++ .../foei/utils/jdbc/ConnectionProvider.java | 55 ++ .../utils/jdbc/ConnectionProviderManager.java | 115 +++ .../utils/jdbc/JndiDataSourceProvider.java | 163 +++++ src/com/idcanet/foei/utils/jdbc/package.html | 61 ++ .../foei/utils/jndi/ContextListWriter.java | 70 ++ .../foei/utils/jndi/MemoryContext.java | 669 ++++++++++++++++++ .../foei/utils/jndi/MemoryContextFactory.java | 61 ++ .../utils/jndi/MemoryContextNameParser.java | 66 ++ src/com/idcanet/foei/utils/jndi/package.html | 61 ++ tests/com/META-INF/foei-config.xml | 13 + tests/com/META-INF/foei.properties | 26 + .../idcanet/foei/tests/SimpleFoeiTests.java | 13 +- .../foei/tests/TestEventThreadListener.java | 22 + 75 files changed, 6511 insertions(+), 1 deletion(-) create mode 100644 lib/commons-beanutils.jar create mode 100644 lib/idcanet-x4o-bin.jar create mode 100644 src/META-INF/events.eld create mode 100644 src/META-INF/filters.eld create mode 100644 src/META-INF/foei-context-defaults.xml create mode 100644 src/META-INF/foei-namespaces.properties create mode 100644 src/META-INF/io.eld create mode 100644 src/META-INF/lang.eld create mode 100644 src/META-INF/logging.eld create mode 100644 src/META-INF/printers.eld create mode 100644 src/com/idcanet/foei/components/io/ErrorOutput.java create mode 100644 src/com/idcanet/foei/components/io/FileOutput.java create mode 100644 src/com/idcanet/foei/components/io/StandardOutput.java create mode 100644 src/com/idcanet/foei/components/logging/Log4jInput.java create mode 100644 src/com/idcanet/foei/components/logging/LoggerHandler.java create mode 100644 src/com/idcanet/foei/components/logging/LoggerInput.java create mode 100644 src/com/idcanet/foei/components/logging/package.html create mode 100644 src/com/idcanet/foei/components/steps/filters/ClassFilter.java create mode 100644 src/com/idcanet/foei/components/steps/filters/DateFilter.java create mode 100644 src/com/idcanet/foei/components/steps/filters/NumberFilter.java create mode 100644 src/com/idcanet/foei/components/steps/filters/StringFilter.java create mode 100644 src/com/idcanet/foei/components/steps/filters/package.html create mode 100644 src/com/idcanet/foei/components/steps/lang/GetBeanPropertyStep.java create mode 100644 src/com/idcanet/foei/components/steps/lang/ListValue.java create mode 100644 src/com/idcanet/foei/components/steps/lang/MapValue.java create mode 100644 src/com/idcanet/foei/components/steps/lang/package.html create mode 100644 src/com/idcanet/foei/components/steps/printers/DatePrinter.java create mode 100644 src/com/idcanet/foei/components/steps/printers/DefaultPrinter.java create mode 100644 src/com/idcanet/foei/components/steps/printers/package.html create mode 100644 src/com/idcanet/foei/core/impl/EventExecutorImpl.java create mode 100644 src/com/idcanet/foei/core/impl/EventExecutorManagerImpl.java create mode 100644 src/com/idcanet/foei/core/impl/EventExecutorThreadFactory.java create mode 100644 src/com/idcanet/foei/core/impl/EventThreadListenersRunnableWrapper.java create mode 100644 src/com/idcanet/foei/core/impl/FoeiConfiguratorImpl.java create mode 100644 src/com/idcanet/foei/core/impl/FoeiContextImpl.java create mode 100644 src/com/idcanet/foei/core/impl/FoeiEventBindingRuleHandler.java create mode 100644 src/com/idcanet/foei/core/impl/FoeiProcessImpl.java create mode 100644 src/com/idcanet/foei/core/impl/FoeiProcessManagerImpl.java create mode 100644 src/com/idcanet/foei/core/impl/FoeiProcessRunnableWrapper.java create mode 100644 src/com/idcanet/foei/core/impl/ObjectBindingsManagerImpl.java create mode 100644 src/com/idcanet/foei/core/impl/X2OExecutorImpl.java create mode 100644 src/com/idcanet/foei/core/impl/package.html create mode 100644 src/com/idcanet/foei/core/x4o/BindAttributeHandler.java create mode 100644 src/com/idcanet/foei/core/x4o/EventStepBindRuleHandler.java create mode 100644 src/com/idcanet/foei/core/x4o/IdAttributeHandler.java create mode 100644 src/com/idcanet/foei/core/x4o/ObjectBindingElement.java create mode 100644 src/com/idcanet/foei/core/x4o/SetParameterElement.java create mode 100644 src/com/idcanet/foei/core/x4o/package.html create mode 100644 src/com/idcanet/foei/event/annotations/SetEventPort.java create mode 100644 src/com/idcanet/foei/event/annotations/SetEventPorts.java create mode 100644 src/com/idcanet/foei/server/config/FoeiConfigContext.java create mode 100644 src/com/idcanet/foei/server/config/FoeiConfigParser.java create mode 100644 src/com/idcanet/foei/server/config/FoeiContextXMLTagHandler.java create mode 100644 src/com/idcanet/foei/server/config/package.html create mode 100644 src/com/idcanet/foei/server/startup/FoeiStartupListener.java create mode 100644 src/com/idcanet/foei/server/startup/package.html create mode 100644 src/com/idcanet/foei/utils/beans/BeanProperty.java create mode 100644 src/com/idcanet/foei/utils/beans/BeanPropertyComparator.java create mode 100644 src/com/idcanet/foei/utils/beans/NumberComparator.java create mode 100644 src/com/idcanet/foei/utils/beans/package.html create mode 100644 src/com/idcanet/foei/utils/jdbc/ConnectionFactory.java create mode 100644 src/com/idcanet/foei/utils/jdbc/ConnectionProvider.java create mode 100644 src/com/idcanet/foei/utils/jdbc/ConnectionProviderManager.java create mode 100644 src/com/idcanet/foei/utils/jdbc/JndiDataSourceProvider.java create mode 100644 src/com/idcanet/foei/utils/jdbc/package.html create mode 100644 src/com/idcanet/foei/utils/jndi/ContextListWriter.java create mode 100644 src/com/idcanet/foei/utils/jndi/MemoryContext.java create mode 100644 src/com/idcanet/foei/utils/jndi/MemoryContextFactory.java create mode 100644 src/com/idcanet/foei/utils/jndi/MemoryContextNameParser.java create mode 100644 src/com/idcanet/foei/utils/jndi/package.html create mode 100644 tests/com/META-INF/foei-config.xml create mode 100644 tests/com/META-INF/foei.properties create mode 100644 tests/com/idcanet/foei/tests/TestEventThreadListener.java diff --git a/.classpath b/.classpath index c604d75..2ed30db 100644 --- a/.classpath +++ b/.classpath @@ -3,5 +3,7 @@ + + diff --git a/lib/commons-beanutils.jar b/lib/commons-beanutils.jar new file mode 100644 index 0000000000000000000000000000000000000000..b1b89c9c921f16af22a88db3ff28975a8e40d886 GIT binary patch literal 188671 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%0AuzmTP^8%%8$0hKGc~D7IJ#Os6p%#?U$R=8t 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%0AbJhvm+16c1RgH~LiZp0 zCG@&o1Z;D-?>nTy*Os;hI-c;<`#*@AZx}~P&00JR*0t3PyoA+CT{D*|OgHRWj zmWu(z7Q_9NO}{0;?glrohtQ$;AJO3G=leB;ncGvB83e;EgCVf6?@z(&-9JD$+&mG2 ze+-}lr!w=RXRHXX0^EEI(oz-tb1gp(u)vbT7xf`#@Sn7q^p^PHrG>BGLF9=ubjft@ vqhML#Q&12wFrF@Py-P=Heg}f$6KF%%-iDX~dp-n07WgUIj6l3e29N#^b&sKs literal 0 HcmV?d00001 diff --git a/src/META-INF/events.eld b/src/META-INF/events.eld new file mode 100644 index 0000000..fa7a08b --- /dev/null +++ b/src/META-INF/events.eld @@ -0,0 +1,33 @@ + + + + + events.eld + All event foei objects + + + \ No newline at end of file diff --git a/src/META-INF/filters.eld b/src/META-INF/filters.eld new file mode 100644 index 0000000..bc43aef --- /dev/null +++ b/src/META-INF/filters.eld @@ -0,0 +1,57 @@ + + + + + filters.eld + All core foei objects + + + + filter + Filters an object by its eventSteps + com.idcanet.foei.components.lang.Filter + + + + stringFilter + filters an String on a regex + com.idcanet.foei.components.steps.filters.StringFilter + + + + classFilter + filters for a class on an object + com.idcanet.foei.components.steps.filters.ClassFilter + + + + dateFilter + filters an date of an Date + com.idcanet.foei.components.steps.filters.DateFilter + + + \ No newline at end of file diff --git a/src/META-INF/foei-context-defaults.xml b/src/META-INF/foei-context-defaults.xml new file mode 100644 index 0000000..ef2c196 --- /dev/null +++ b/src/META-INF/foei-context-defaults.xml @@ -0,0 +1,23 @@ + + + + + + + + + com.idcanet.foei.core.impl.ObjectBindingsManagerImpl + + diff --git a/src/META-INF/foei-namespaces.properties b/src/META-INF/foei-namespaces.properties new file mode 100644 index 0000000..a7404d9 --- /dev/null +++ b/src/META-INF/foei-namespaces.properties @@ -0,0 +1,18 @@ + +code.http\://foei.idca.nl/eld/events.eld=com.idcanet.x4o.core.DefaultX4OEldElementProvider +file.http\://foei.idca.nl/eld/events.eld=/META-INF/events.eld + +code.http\://foei.idca.nl/eld/filters.eld=com.idcanet.x4o.core.DefaultX4OEldElementProvider +file.http\://foei.idca.nl/eld/filters.eld=/META-INF/filters.eld + +code.http\://foei.idca.nl/eld/io.eld=com.idcanet.x4o.core.DefaultX4OEldElementProvider +file.http\://foei.idca.nl/eld/io.eld=/META-INF/io.eld + +code.http\://foei.idca.nl/eld/lang.eld=com.idcanet.x4o.core.DefaultX4OEldElementProvider +file.http\://foei.idca.nl/eld/lang.eld=/META-INF/lang.eld + +code.http\://foei.idca.nl/eld/logging.eld=com.idcanet.x4o.core.DefaultX4OEldElementProvider +file.http\://foei.idca.nl/eld/logging.eld=/META-INF/logging.eld + +code.http\://foei.idca.nl/eld/printers.eld=com.idcanet.x4o.core.DefaultX4OEldElementProvider +file.http\://foei.idca.nl/eld/printers.eld=/META-INF/printers.eld \ No newline at end of file diff --git a/src/META-INF/io.eld b/src/META-INF/io.eld new file mode 100644 index 0000000..4d9c2e6 --- /dev/null +++ b/src/META-INF/io.eld @@ -0,0 +1,53 @@ + + + + + + io.eld + io foei objects + + + + standardOutput + This Object printer prints to the std-out + com.idcanet.foei.components.io.StandardOutput + + + + + errorOutput + This Object printer prints to the err-out + com.idcanet.foei.components.io.ErrorOutput + + + + fileOutput + This Object printer prints to a file + com.idcanet.foei.components.io.FileOutput + + + \ No newline at end of file diff --git a/src/META-INF/lang.eld b/src/META-INF/lang.eld new file mode 100644 index 0000000..69ecdb7 --- /dev/null +++ b/src/META-INF/lang.eld @@ -0,0 +1,105 @@ + + + + + lang.eld + All core lang foei objects + + + + bind + com.idcanet.foei.core.x4o.BindAttributeHandler + Binds the EventPort to getter + + + + id + com.idcanet.foei.core.x4o.IdAttributeHandler + Adds the object into the context + + + + com.idcanet.foei.core.x4o.EventStepBindRuleHandler + + + + + bind + Binds 2 eventPorts together + com.idcanet.foei.core.x4o.ObjectBindingElement + + + + dummyOutputPort + An dummy output, mostly used to send events into foei. + com.idcanet.foei.components.lang.DummyOutputPort + + + + objectChangedBuffer + Buffers objects an only fires when it is not equal + com.idcanet.foei.components.lang.ObjectChangedBuffer + + + + destroyFoeiProcess + Destroys the current process + com.idcanet.foei.components.lang.DestroyFoeiProcess + + + + setBeanProperty + Sets an property on a bean. + com.idcanet.foei.components.lang.SetBeanProperty + + + + getBeanProperty + Gets an property on a bean. + com.idcanet.foei.components.lang.GetBeanProperty + + + + + getBeanPropertyStep + gets an property of an obeject + com.idcanet.foei.components.steps.lang.GetBeanPropertyStep + + + + mapValue + gets an Value out of an Map + com.idcanet.foei.components.steps.lang.MapValue + + + + listValue + gets an Value out of an List + com.idcanet.foei.components.steps.lang.ListValue + + + \ No newline at end of file diff --git a/src/META-INF/logging.eld b/src/META-INF/logging.eld new file mode 100644 index 0000000..71e9e59 --- /dev/null +++ b/src/META-INF/logging.eld @@ -0,0 +1,35 @@ + + + + + + loggerInput + Java Logger InputHandler + com.idcanet.foei.components.logging.LoggerInput + + + \ No newline at end of file diff --git a/src/META-INF/printers.eld b/src/META-INF/printers.eld new file mode 100644 index 0000000..0a5e19d --- /dev/null +++ b/src/META-INF/printers.eld @@ -0,0 +1,61 @@ + + + + + + printers.eld + A few standaard (step)printers + + + + + defaultPrinter + This EventStep uses to toString() to print an object. + com.idcanet.foei.components.steps.printers.DefaultPrinter + + + prefix + java.lang.String + null + Prints the prefix of this printer + + + postfix + java.lang.String + null + Prints the postfix of this printer + + + + + + datePrinter + This eventStep prints an date object including formating + com.idcanet.foei.components.steps.printers.DatePrinter + + + \ No newline at end of file diff --git a/src/com/idcanet/foei/components/io/ErrorOutput.java b/src/com/idcanet/foei/components/io/ErrorOutput.java new file mode 100644 index 0000000..9ea4d17 --- /dev/null +++ b/src/com/idcanet/foei/components/io/ErrorOutput.java @@ -0,0 +1,72 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.components.io; + +import com.idcanet.foei.event.AbstractEventInputStepController; +import com.idcanet.foei.event.EventPort; +import com.idcanet.foei.event.EventPortType; +import com.idcanet.foei.event.EventStep; +import com.idcanet.foei.event.IllegalEventPortNameException; + +/** + * Prints the EventSteps to the System.err + * + * @author Willem Cazander + * @version 1.0 Jan 25, 2006 + */ +public class ErrorOutput extends AbstractEventInputStepController +{ + /** v1.0 */ + static final long serialVersionUID = 10l; + + /** + * Creates an ErrorOutput + */ + public ErrorOutput() { + addInputPort(EventPort.INPUT); + } + + // ----------- EventInput + + public void doEvent(EventPort eventPort,Object object) throws IllegalEventPortNameException { + if(EventPortType.input!=eventPort.getEventPortType()) { + throw new IllegalEventPortNameException("Not excisting input EventPort: "+eventPort.getName()); + } + System.err.println(processEventSteps(object)); + } + + public Object processEventSteps(Object object) { + StringBuffer buff = new StringBuffer(); + for(EventStep e:getEventSteps()) { + if(object==null) { + return null; + } + buff.append((String)e.processObject(object)); + } + return buff; + } +} diff --git a/src/com/idcanet/foei/components/io/FileOutput.java b/src/com/idcanet/foei/components/io/FileOutput.java new file mode 100644 index 0000000..f4cb001 --- /dev/null +++ b/src/com/idcanet/foei/components/io/FileOutput.java @@ -0,0 +1,36 @@ + +package com.idcanet.foei.components.io; +/* + +import java.util.ArrayList; +import java.util.List; +import java.util.Iterator; + +public class FileOutput extends AbstractEventInput +{ + static final String INPUT = "input"; + private ArrayList printers = new ArrayList(4); + + public FileOutput() + { + inputList.add(INPUT); + } + + + // ----------- EventInput + + public void doEvent(String inputName,Object object) + { + Iterator printerWalker = printers.iterator(); + //System.out.print("STDOUT:"); + while(printerWalker.hasNext()) + { + EventStep eventStep = (EventStep)printerWalker.next(); + String out = (String)eventStep.processObject(object); + System.out.print(out); + } + System.out.println(""); + } + +} +*/ \ No newline at end of file diff --git a/src/com/idcanet/foei/components/io/StandardOutput.java b/src/com/idcanet/foei/components/io/StandardOutput.java new file mode 100644 index 0000000..e9524aa --- /dev/null +++ b/src/com/idcanet/foei/components/io/StandardOutput.java @@ -0,0 +1,73 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.components.io; + +import com.idcanet.foei.event.AbstractEventInputStepController; +import com.idcanet.foei.event.EventPort; +import com.idcanet.foei.event.EventPortType; +import com.idcanet.foei.event.EventStep; +import com.idcanet.foei.event.IllegalEventPortNameException; + +/** + * Prints the EventSteps to the System.out + * + * @author Willem Cazander + * @version 1.0 Jan 25, 2006 + */ +public class StandardOutput extends AbstractEventInputStepController { + + /** v1.0 */ + static final long serialVersionUID = 10l; + + /** + * Creates an StandardOutput + * + */ + public StandardOutput() { + addInputPort(EventPort.INPUT); + } + + // ----------- EventInput + + public void doEvent(EventPort eventPort,Object object) throws IllegalEventPortNameException { + if(EventPortType.input!=eventPort.getEventPortType()) { + throw new IllegalEventPortNameException("Not excisting input EventPort: "+eventPort.getName()); + } + System.out.println(processEventSteps(object)); + } + + public Object processEventSteps(Object object) { + StringBuffer buff = new StringBuffer(); + for(EventStep e:getEventSteps()) { + if(object==null) { + return null; + } + buff.append((String)e.processObject(object)); + } + return buff; + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/components/logging/Log4jInput.java b/src/com/idcanet/foei/components/logging/Log4jInput.java new file mode 100644 index 0000000..cddb382 --- /dev/null +++ b/src/com/idcanet/foei/components/logging/Log4jInput.java @@ -0,0 +1,64 @@ +package com.idcanet.foei.components.logging; +/* + +package com.mbuyu.foei.handlers.log4j; + +import java.net.*; +import java.io.*; + +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.Layout; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.apache.log4j.Layout; +import org.apache.log4j.PatternLayout; +import org.apache.log4j.WriterAppender; +import org.apache.log4j.net.SocketNode; + +public class RequestCollector implements Runnable { + + private Socket reqSocket; + private SocketNode reqNode; + private String host; + private int port; + static final String fileName = "rtrace"; + static final Logger logger = Logger.getLogger("RequestCollector.class"); + + public RequestCollector (int port, String host) { + super(); + this.host = host; + this.port = port; + } + + public void run() { + try { + BasicConfigurator.configure(); + PrintWriter writer = new PrintWriter (new FileWriter(fileName)); + Layout layout = new PatternLayout("%d{ABSOLUTE} %c{1} %m\n"); + WriterAppender appender = new WriterAppender(layout, writer); + appender.setImmediateFlush(true); + LogManager.getRootLogger().removeAllAppenders(); + LogManager.getRootLogger().addAppender(appender); + appender.activateOptions(); + logger.addAppender(appender); + reqSocket = new Socket(host, port); + System.out.println("Created Socket"); + reqNode = new SocketNode(reqSocket, LogManager.getLoggerRepository()); + System.out.println("Created SocketNode"); + new Thread(reqNode).start(); + System.out.println("After thread (reqNode)"); + + } catch (Exception e) { + e.printStackTrace(); + System.out.println(e); + } + } + + public static void main (String args[]) { + System.out.println("B4 Starting"); + RequestCollector rq = new RequestCollector(9998, "some-host"); + new Thread(rq).start(); + System.out.println("Completed"); + } +} +*/ \ No newline at end of file diff --git a/src/com/idcanet/foei/components/logging/LoggerHandler.java b/src/com/idcanet/foei/components/logging/LoggerHandler.java new file mode 100644 index 0000000..e25767c --- /dev/null +++ b/src/com/idcanet/foei/components/logging/LoggerHandler.java @@ -0,0 +1,65 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.components.logging; + +import java.util.HashMap; +import java.util.logging.Logger; +import java.util.logging.Handler; +import java.util.logging.LogRecord; + +/** + * + * + * @author Willem Cazander + * @version 1.0 Jan 25, 2006 + */ +public class LoggerHandler extends Handler +{ + private Logger logger = Logger.getLogger(this.getClass().getName()); + private LoggerInput loggerInput = null; + + public LoggerHandler(LoggerInput loggerInput) + { + this.loggerInput=loggerInput; + logger.addHandler(this); + } + + // ------------ handler + + public void publish(LogRecord record) { + HashMap event = new HashMap(); + event.put("message",record.getMessage()); + event.put("level",record.getLevel().getName()); + loggerInput.sendMessage(event); + } + + public void flush() { + } + + public void close() { + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/components/logging/LoggerInput.java b/src/com/idcanet/foei/components/logging/LoggerInput.java new file mode 100644 index 0000000..704c132 --- /dev/null +++ b/src/com/idcanet/foei/components/logging/LoggerInput.java @@ -0,0 +1,67 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.components.logging; + +import com.idcanet.foei.core.FoeiProcessFactory; +import com.idcanet.foei.event.AbstractEventOutput; +import com.idcanet.foei.event.EventPort; + +import java.util.Map; + +/** + * Reseives java logging messages + * + * @author Willem Cazander + * @version 1.0 Jan 25, 2006 + */ +public class LoggerInput extends AbstractEventOutput +{ + /** v1.0 */ + static final long serialVersionUID = 10l; + /** */ + static final String OUTPUT = "output"; + + /** + * Creates an LoggerInput + * + */ + public LoggerInput() { + // define an outpur source. + addOutputPort(OUTPUT,Map.class); + new LoggerHandler(this); + } + + /** + * + * @param event + */ + public void sendMessage(Map event) { + FoeiProcessFactory.getFoeiProcess().executeEvent(getOutputPort(EventPort.OUTPUT),event); + //FoeiInstance foeiInstance = FoeiServer.getFoeiInstance(); + //foeiInstance.getObjectBindingsManager().sendEventOutput(getID(),OUTPUT,event); + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/components/logging/package.html b/src/com/idcanet/foei/components/logging/package.html new file mode 100644 index 0000000..ee5a4dc --- /dev/null +++ b/src/com/idcanet/foei/components/logging/package.html @@ -0,0 +1,55 @@ + + + + + + +Some EventObjects for log handing.
+ + + +

Related Documentation

+ +None. + + + + + \ No newline at end of file diff --git a/src/com/idcanet/foei/components/steps/filters/ClassFilter.java b/src/com/idcanet/foei/components/steps/filters/ClassFilter.java new file mode 100644 index 0000000..84caf0f --- /dev/null +++ b/src/com/idcanet/foei/components/steps/filters/ClassFilter.java @@ -0,0 +1,88 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.components.steps.filters; + +import com.idcanet.foei.event.AbstractEventStepController; + +/** + * Filters an object and checks for the className. + * + * @author Willem Cazander + * @version 1.0 26/01/2005 + */ +public class ClassFilter extends AbstractEventStepController +{ + /** v1.0 */ + static final long serialVersionUID = 10l; + /** The class name to match */ + private String className = null; + + /** + * Sets the className which the filtered object has to have. + * @param className The className. + */ + public void setClassName(String className) + { + this.className=className; + } + + /** + * Returns the className on which this filter filters. + * @return The className. + */ + public String getClassName() + { + return className; + } + + /** + * Process an object.
+ * This checks if the objects class equals that of the className. + * @return The object or null is not succesfull. + */ + public Object processObject(Object object) + { + if(object==null) + { + return null; + } + Class[] classes = object.getClass().getClasses(); + System.out.println("ClassFilter filter: "+object+" on "+className+" classes: "+classes.length); + for(int i=0;i0) { + return null; + } + return object; + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/components/steps/filters/StringFilter.java b/src/com/idcanet/foei/components/steps/filters/StringFilter.java new file mode 100644 index 0000000..db7bd9e --- /dev/null +++ b/src/com/idcanet/foei/components/steps/filters/StringFilter.java @@ -0,0 +1,158 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.components.steps.filters; + +import com.idcanet.foei.event.AbstractEventStepController; + +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Filters an String object. + * + * @author Willem Cazander + * @version 1.0 26/01/2005 + */ +public class StringFilter extends AbstractEventStepController +{ + /** v1.0 */ + static final long serialVersionUID = 10l; + private int minLength=0; + private int maxLength=0; + private Logger logger = Logger.getLogger(this.getClass().getName()); + private Pattern pattern = null; + + /** + * Emty constuctor. + */ + public StringFilter() { + } + + // -------------- (bean)properties. + + /** + * Sets the regulare expression on which this object filters an String.
+ *
+ * When set to Null matching is disabled.
+ * + * @param regex The regulare expression to match to. + */ + public void setRegEx(String regex) { + pattern = Pattern.compile(regex); + } + /** + * Returns the current regulare expression. + * @return The regulare expression. + */ + public String getRegEx() { + if(pattern==null) { + return null; + } + return pattern.pattern(); + } + + /** + * Set the minimal length the filtered object has to be.
+ *
+ * When set to -1 testing is disabled.
+ * + * @param minLength The minimal length to match. + */ + public void setMinLength(int minLength) { + this.minLength=minLength; + } + + /** + * Returns the current minimal length of this filter. + * @return The minimal length. + */ + public int getMinLength() { + return minLength; + } + + /** + * Set the maximal length of the filters string object.
+ *
+ * When set to -1 testing is disabled.
+ * + * @param maxLength + */ + public void setMaxLength(int maxLength) { + this.maxLength=maxLength; + } + + /** + * Returns the current maximal length. + * @return the maximal length. + */ + public int getMaxLength() { + return maxLength; + } + + // -------------- eventStep + + /** + * Filters an Object. + * If it not an String then null will be returned. + * Likewise when the String object has not matched to an certain + * propertie then also null will be returned. + * + * @param object The Object thats get filtered. + * @return null if object was not mached else the object returns. + */ + public Object processObject(Object object) { + + if(!(object instanceof String)) { + return null; + } + String string = (String)object; + + if(pattern==null) { + + } + + if(pattern!=null) { + // test if regex matches + Matcher m = pattern.matcher(string); + if(!m.find()) { + return null; + } + } + + // test min length + if(minLength!=0 && string.length()>minLength) { + return null; + } + // test max length + if(maxLength!=0 && string.length() + + + + + +EventSteps which filter an Object.
+ + + +

Related Documentation

+ +None. + + + + + \ No newline at end of file diff --git a/src/com/idcanet/foei/components/steps/lang/GetBeanPropertyStep.java b/src/com/idcanet/foei/components/steps/lang/GetBeanPropertyStep.java new file mode 100644 index 0000000..245fe89 --- /dev/null +++ b/src/com/idcanet/foei/components/steps/lang/GetBeanPropertyStep.java @@ -0,0 +1,78 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.components.steps.lang; + +import com.idcanet.foei.event.AbstractEventStepController; + +import org.apache.commons.beanutils.BeanUtils; + +/** + * Gets the property of an java bean. + * + * @author Willem Cazander + * @version 1.0 Feb 9, 2006 + */ +public class GetBeanPropertyStep extends AbstractEventStepController +{ + /** v1.0 */ + static final long serialVersionUID = 10l; + /** Holds the key which contains the object in the map. */ + private String property = null; + + + //----------- get/set functions + + public void setProperty(String property) { + this.property=property; + } + + public String getProperty() { + return property; + } + + // -------------------- EventStep + + /** + * Proces an Object, when property is correcly found then + * it is processed by the eventSteps of the object. + */ + public Object processObject(Object object) { + if(property==null) { + return null; + } + Object result = null; + try { + result = BeanUtils.getProperty(object,property); + } catch (Exception e) { + //logger.log(Level.WARNING,"property:"+property+" is not an property of object: "+object.getClass().getName(),e); + e.printStackTrace(); + return null; + } + return processEventSteps(result); + } +} + diff --git a/src/com/idcanet/foei/components/steps/lang/ListValue.java b/src/com/idcanet/foei/components/steps/lang/ListValue.java new file mode 100644 index 0000000..1c4f5ef --- /dev/null +++ b/src/com/idcanet/foei/components/steps/lang/ListValue.java @@ -0,0 +1,79 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.components.steps.lang; + +import com.idcanet.foei.event.AbstractEventStepController; + +import java.util.List; + +/** + * Gets an Value out of an List + * + * @author Willem Cazander + * @version 1.0 Feb 9, 2006 + */ +public class ListValue extends AbstractEventStepController +{ + /** v1.0 */ + static final long serialVersionUID = 10l; + /** Holds the index which contains the object in the map. */ + private String index = null; + + static private final String FIRST = "FIRST"; + static private final String LAST = "LAST"; + + // bean + + public void setIndex(String index) { + this.index=index; + } + public String getIndex() { + return index; + } + public Object processObject(Object object) { + + if(!(object instanceof List)) { + return null; + } + List list = (List)object; + + if(FIRST.equalsIgnoreCase(index)) { + return processEventSteps(list.get(0)); + } + if(LAST.equalsIgnoreCase(index)) { + return processEventSteps(list.get(list.size())); + } + try { + int listIndex = new Integer(index); + return processEventSteps(list.get(listIndex)); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + +} \ No newline at end of file diff --git a/src/com/idcanet/foei/components/steps/lang/MapValue.java b/src/com/idcanet/foei/components/steps/lang/MapValue.java new file mode 100644 index 0000000..2237e5d --- /dev/null +++ b/src/com/idcanet/foei/components/steps/lang/MapValue.java @@ -0,0 +1,88 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.components.steps.lang; + +import com.idcanet.foei.event.AbstractEventStepController; + +import java.util.Map; + +/** + * This EventStep can have nesting EventSteps. + * It it get the object out of the map object which is processed and + * let is process by an added EventStep object. + * + * @author Willem Cazander + * @version 1.0 28/03/2004 + */ +public class MapValue extends AbstractEventStepController +{ + /** v1.0 */ + static final long serialVersionUID = 10l; + /** Holds the key which contains the object in the map. */ + private String key = null; + + + //----------- get/set functions + + /** + * Sets the key which is used to lookup an object in an Map.
+ * Which gets returned by the processObject() of EventStep.
+ * @param key The key of an object in an Map. + */ + public void setKey(String key) { + this.key=key; + } + + /** + * Gets the key of the Map. + * @return The current key. + */ + public String getKey() { + return key; + } + + + // -------------------- EventStep + + /** + * Process an object.
+ * This is done by the EventStep Object which is added.
+ *
+ * Current implementation returns only the object which is returned
+ * by the last EventStep in the List.
+ * + */ + public Object processObject(Object object) { + if(key==null) { + return null; + } + Map map = (Map)object; + object = map.get(key); + return processEventSteps(object); + } +} + diff --git a/src/com/idcanet/foei/components/steps/lang/package.html b/src/com/idcanet/foei/components/steps/lang/package.html new file mode 100644 index 0000000..e0601c5 --- /dev/null +++ b/src/com/idcanet/foei/components/steps/lang/package.html @@ -0,0 +1,57 @@ + + + + + + +EventSteps which Gets of object from an Object.
+ +

Package Specification

+ + + +

Related Documentation

+ +None. + + + + + \ No newline at end of file diff --git a/src/com/idcanet/foei/components/steps/printers/DatePrinter.java b/src/com/idcanet/foei/components/steps/printers/DatePrinter.java new file mode 100644 index 0000000..f43bb2d --- /dev/null +++ b/src/com/idcanet/foei/components/steps/printers/DatePrinter.java @@ -0,0 +1,88 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.components.steps.printers; + +import com.idcanet.foei.event.AbstractEventStep; + +import java.util.Date; +import java.text.SimpleDateFormat; + +/** + * Print an Date object. + * + * @author Willem Cazander + * @version 1.0 26/01/2005 + */ +public class DatePrinter extends AbstractEventStep +{ + /** v1.0 */ + static final long serialVersionUID = 10l; + /** An SimpleDateFormat formated date format template string */ + private SimpleDateFormat dateFormat=null; + + /** + * Emty constructor + */ + public DatePrinter() { + } + + /** + * Set the format in which the Date object is printed. + * @param pattern An SimpleDateFormat formatted string. + */ + public void setSimpleDateFormat(String pattern) { + // else use defaults !!! + // TODO log this event ... but don't let is stop it. + try { + dateFormat = new SimpleDateFormat(pattern); + } catch (NullPointerException npe) { + dateFormat = new SimpleDateFormat(); + } catch (IllegalArgumentException iae) { + dateFormat = new SimpleDateFormat(); + } + } + /** + * Returns the SimpleDateFormat formatted string being used to format an Date. + * @return The SimpleDateFormat string. + */ + public String getSimpleDateFormat() { + return dateFormat.toPattern(); + } + + /** + * Prints an Date object.
+ *
+ * If object is not an Date "" is printed.
+ * + * @param object The Object being printed. + * @return The String format of the object. + */ + public Object processObject(Object object) { + Date date = (Date)object; + return dateFormat.format(date); + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/components/steps/printers/DefaultPrinter.java b/src/com/idcanet/foei/components/steps/printers/DefaultPrinter.java new file mode 100644 index 0000000..7558a2e --- /dev/null +++ b/src/com/idcanet/foei/components/steps/printers/DefaultPrinter.java @@ -0,0 +1,98 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.components.steps.printers; + +import com.idcanet.foei.event.AbstractEventStep; + +/** + * Prints the toString of any java object.
+ * With an optioneal pre/post-fix.
+ * + * @author Willem Cazander + * @version 1.0 17/11/2004 + */ +public class DefaultPrinter extends AbstractEventStep +{ + /** v1.0 */ + static final long serialVersionUID = 10l; + /** The preFix */ + private String preFix = null; + /** The postFix */ + private String postFix = null; + + /** + * Sets the prefix + * @param preFix The String printed before the object. + */ + public void setPreFix(String preFix) { + this.preFix=preFix; + } + + /** + * Returns the prefix. + * @return The String printed before the object. + */ + public String getPreFix() { + return preFix; + } + + /** + * Sets the postfix. + * @param postFix The String printed after the object. + */ + public void setPostFix(String postFix) { + this.postFix=postFix; + } + + /** + * Returns the postfix. + * @return The String printed after the object. + */ + public String getPostFix() { + return postFix; + } + + /** + *This methode returns an String represantation of an object + *in the default toSting() of the object. + *@param object The object which need to be printed. + *@return The string represantation of the object. + */ + public Object processObject(Object object) { + String returnString = ""; + if(preFix!=null) { + returnString = preFix; + } + if(object!=null) { + returnString += object.toString(); + } + if(postFix!=null) { + returnString += postFix; + } + return returnString; + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/components/steps/printers/package.html b/src/com/idcanet/foei/components/steps/printers/package.html new file mode 100644 index 0000000..c9b2d83 --- /dev/null +++ b/src/com/idcanet/foei/components/steps/printers/package.html @@ -0,0 +1,61 @@ + + + + + + +EventSteps which print objects
+ +

Package Specification

+ +
    +
  • Full J2SE 5 compatible
  • +
  • Small package
  • +
+ + +

Related Documentation

+ +None. + + + + + \ No newline at end of file diff --git a/src/com/idcanet/foei/core/impl/EventExecutorImpl.java b/src/com/idcanet/foei/core/impl/EventExecutorImpl.java new file mode 100644 index 0000000..ee98e9f --- /dev/null +++ b/src/com/idcanet/foei/core/impl/EventExecutorImpl.java @@ -0,0 +1,126 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.core.impl; + +import com.idcanet.foei.core.EventExecutor; +import com.idcanet.foei.core.FoeiProcess; +import com.idcanet.foei.core.FoeiProcessFactory; +import com.idcanet.foei.event.EventInput; +import com.idcanet.foei.event.EventPort; +import com.idcanet.foei.event.EventPortType; + +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Reuable EventExecutors + * + * @author Willem Cazander + * @version 1.0 Jan 19, 2006 + */ +public class EventExecutorImpl implements EventExecutor { + + /** The logger to log to. */ + private Logger logger = null; + /** The event obect. */ + private Object eventObject = null; + /** The eventport */ + private EventPort eventPort = null; + /** True when ready */ + private boolean ready = false; + + /** + * Creates an EventExecutor + */ + public EventExecutorImpl() { + logger = Logger.getLogger(EventExecutorImpl.class.getName()); + } + + /** + * @see EventExecutor#setEventObject(Object) + */ + public void setEventObject(Object eventObject) { + this.eventObject=eventObject; + ready = false; + } + + /** + * @see EventExecutor#setEventPort(EventPort) + */ + public void setEventPort(EventPort eventPort) { + if(eventPort==null) { + throw new NullPointerException("EventPort may not be null."); + } + this.eventPort=eventPort; + ready = false; + } + + /** + * @see EventExecutor#isReady() + */ + public boolean isReady() { + return ready; + } + + /** + * @see Runnable#run() + */ + public void run() { + if(eventPort==null) { + logger.warning("Can't execute event on null eventPort."); + return; + } + ready = false; + try { + FoeiProcess foeiProcess = FoeiProcessFactory.getFoeiProcess(); + if(eventPort.getEventPortType()==EventPortType.input) { + EventInput eventInput = (EventInput)eventPort.getEventObject(); + eventInput.doEvent(eventPort,eventObject); + return; + } + if(eventPort.getEventPortType()==EventPortType.output) { + List bindings = foeiProcess.getBindings(eventPort); + for(EventPort port:bindings) { + EventInput eventInput = (EventInput)port.getEventObject(); + if(port.isImmediate()) { + logger.finer("Executing event of: "+port.getEventObject()+" port:"+port.getName()+" object: "+eventObject); + eventInput.doEvent(port,eventObject); + } else { + logger.finest("Adding event to event queue"); + foeiProcess.executeEvent(port,eventObject); + } + } + return; + } + } catch (Exception e) { + logger.log(Level.WARNING,"Error while Executing Event",e); + } finally { + ready = true; + } + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/core/impl/EventExecutorManagerImpl.java b/src/com/idcanet/foei/core/impl/EventExecutorManagerImpl.java new file mode 100644 index 0000000..e55dc61 --- /dev/null +++ b/src/com/idcanet/foei/core/impl/EventExecutorManagerImpl.java @@ -0,0 +1,201 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.core.impl; + +import com.idcanet.foei.core.EventExecutor; +import com.idcanet.foei.core.EventExecutorManager; +import com.idcanet.foei.core.EventThreadListener; +import com.idcanet.foei.core.FoeiContext; +import com.idcanet.foei.core.FoeiProcess; +import com.idcanet.foei.core.FoeiProcessFactory; +import com.idcanet.foei.event.EventPort; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Defines the EventExecutorManager implementation + * + * @author Willem Cazander + * @version 1.0 Jan 20, 2006 + */ +public class EventExecutorManagerImpl implements EventExecutorManager { + + /** The logger to log to. */ + private Logger logger = null; + /** The thread pool */ + private ThreadPoolExecutor threadPoolExecutor = null; + /** The EventThreadListeners */ + private List eventThreadListeners = null; + /** The class for the EventExecutor */ + private Class eventExecutorClass = null; + /** + * Creates an EventExecutorManagerImpl ans inits the logger. + */ + public EventExecutorManagerImpl() { + logger = Logger.getLogger(EventExecutorManagerImpl.class.getName()); + eventThreadListeners = new ArrayList(1); + } + + // ============= EventExecutorManager + + /** + * Executes an Event mostly send from an EventObject. + * @see EventExecutorManager#executeEvent(Object, EventPort) + */ + public void executeEvent(EventPort eventPort,Object eventObject) { + executeEvent(eventPort,eventObject,FoeiProcessFactory.getFoeiProcess()); + } + + /** + * Executes an EventPort with object in an FoeiProcess. + * @param eventPort + * @param eventObject + * @param foeiProcess + */ + public void executeEvent(EventPort eventPort,Object eventObject,FoeiProcess foeiProcess) { + EventExecutor e = null; + try { + e = (EventExecutor)eventExecutorClass.newInstance(); + } catch (Exception ee) { + logger.log(Level.WARNING,"Error Creating EventExecutor: "+ee.getMessage(),ee); + return; + } + e.setEventObject(eventObject); + e.setEventPort(eventPort); + if(eventPort.isImmediate()) { + e.run(); + } else { + // mmmm + execute(e,foeiProcess); + } + } + + /** + * Executes an event. + * @see EventExecutorManager#execute(Runnable) + */ + public void execute(Runnable runnable,FoeiProcess foeiProcess) { + if(threadPoolExecutor==null) { + throw new IllegalStateException("EventExecutorManager has not been started."); + } + threadPoolExecutor.execute(new FoeiProcessRunnableWrapper(runnable,foeiProcess)); + } + + /** + * Starts the ThreadPool + * @see EventExecutorManager#start() + */ + public void start(FoeiContext foeiContext) { + if(foeiContext==null) { + throw new NullPointerException("FoeiContext may not be null."); + } + logger.info("Starting EventExecutorManagerImpl"); + + try { + eventExecutorClass = FoeiConfiguratorImpl.newEventExecutorClass(foeiContext.getStartProperties()); + } catch (ClassNotFoundException cce) { + logger.log(Level.WARNING,"Error getting eventExecutor class: "+cce.getMessage(),cce); + throw new RuntimeException("Could not get EventExecutor class: "+cce.getMessage(),cce); + } + + EventExecutorThreadFactory tf = new EventExecutorThreadFactory(foeiContext); + ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor ( + FoeiConfiguratorImpl.getEventExecutorPoolCoreSize(foeiContext.getStartProperties()), + FoeiConfiguratorImpl.getEventExecutorPoolMaxSize(foeiContext.getStartProperties()), + FoeiConfiguratorImpl.getEventExecutorPoolKeepAlive(foeiContext.getStartProperties()), + TimeUnit.SECONDS, + new LinkedBlockingQueue(), + tf + ); + threadPoolExecutor.prestartAllCoreThreads(); + setThreadPoolExecutor(threadPoolExecutor); + } + + /** + * Stops the ThreadPool + * @see EventExecutorManager#stop() + */ + public void stop(FoeiContext foeiContext) { + if(threadPoolExecutor==null) { + throw new IllegalStateException("EventExecutorManager has not been started."); + } + logger.info("Stoping EventExecutorManagerImpl"); + threadPoolExecutor.shutdown(); + threadPoolExecutor=null; + } + + /** + * @see EventExecutorManager#getEventThreadListeners() + */ + public List getEventThreadListeners() { + return eventThreadListeners; + } + + /** + * @see EventExecutorManager#addEventThreadListener(EventThreadListener) + */ + public void addEventThreadListener(EventThreadListener eventThreadListener) throws IllegalStateException { + if(eventThreadListener==null) { + throw new NullPointerException("eventThreadListener may not be null."); + } + if(threadPoolExecutor!=null) { + throw new IllegalStateException("threadPoolExecutor is already started."); + } + eventThreadListeners.add(eventThreadListener); + } + + // ========== other methods: + + /** + * Can be used when override from this class. + * note: + * This method is not an interface method. + * @param threadPoolExecutor + */ + public void setThreadPoolExecutor(ThreadPoolExecutor threadPoolExecutor) { + if(this.threadPoolExecutor!=null) { + throw new IllegalStateException("ThreadPoolExecutor may only be set once"); + } + this.threadPoolExecutor=threadPoolExecutor; + } + + /** + * Returns the ThreadPoolExecutor + */ + public ThreadPoolExecutor getThreadPoolExecutor() { + if(threadPoolExecutor==null) { + throw new IllegalStateException("EventExecutorManager has not been started."); + } + return threadPoolExecutor; + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/core/impl/EventExecutorThreadFactory.java b/src/com/idcanet/foei/core/impl/EventExecutorThreadFactory.java new file mode 100644 index 0000000..9c250f4 --- /dev/null +++ b/src/com/idcanet/foei/core/impl/EventExecutorThreadFactory.java @@ -0,0 +1,91 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.core.impl; + +import com.idcanet.foei.core.FoeiContext; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Logger; + +/** + * Creates Thread for the threadpool and injects the threadpool runnable object with the + * FoeiContext. + * + * @author Willem Cazander + * @version 1.0 Feb 7, 2006 + */ +public class EventExecutorThreadFactory implements ThreadFactory +{ + /** The pool number. */ + static private final AtomicInteger poolNumber = new AtomicInteger(1); + /** The thread group. */ + private final ThreadGroup group; + /** The thread number. */ + private final AtomicInteger threadNumber = new AtomicInteger(1); + /** The name prefix. */ + private String namePrefix = null; + /** The FoeiContext to wrap in the thread. */ + private FoeiContext foeiContext = null; + /** The logger to log to. */ + private Logger logger = null; + + /** + * Creates an EventExecutorThreadFactory + * @param foeiContext + */ + public EventExecutorThreadFactory(FoeiContext foeiContext) { + if(foeiContext==null) { + throw new NullPointerException("FoeiContext may not be null."); + } + logger = Logger.getLogger(EventExecutorThreadFactory.class.getName()); + this.foeiContext=foeiContext; + SecurityManager s = System.getSecurityManager(); + group = (s != null)? s.getThreadGroup():Thread.currentThread().getThreadGroup(); + namePrefix = "foei-"+poolNumber.getAndIncrement()+"-thread-"; + } + + /** + * Creates an new Thread and wrappes the Runnable with the FoeiContextRunnableWrapper + */ + public Thread newThread(Runnable r) { + Runnable runnable = new EventThreadListenersRunnableWrapper(r,foeiContext); + Thread t = new Thread(group,runnable,namePrefix+threadNumber.getAndIncrement(),0); + logger.info("Created new Executor Thread: "+t.getName()); + if (t.isDaemon()) { + t.setDaemon(false); + } + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + } +} + + + + diff --git a/src/com/idcanet/foei/core/impl/EventThreadListenersRunnableWrapper.java b/src/com/idcanet/foei/core/impl/EventThreadListenersRunnableWrapper.java new file mode 100644 index 0000000..d4b1e65 --- /dev/null +++ b/src/com/idcanet/foei/core/impl/EventThreadListenersRunnableWrapper.java @@ -0,0 +1,75 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.core.impl; + +import com.idcanet.foei.core.EventThreadListener; +import com.idcanet.foei.core.FoeiContext; + +/** + * Call all EventTheadListeners of an FoeiContext + * + * @author Willem Cazander + * @version 1.0 Feb 8, 2006 + */ +public class EventThreadListenersRunnableWrapper implements Runnable { + + /** The wrapped runnable object. */ + private Runnable runnable = null; + /** The FoeiContext for this thread. */ + private FoeiContext foeiContext = null; + + /** + * creates an EventThreadListenersRunnableWrapper + * @param runnable + * @param foeiContext + */ + public EventThreadListenersRunnableWrapper(Runnable runnable,FoeiContext foeiContext) { + if(runnable==null) { + throw new NullPointerException("runnable may not be null."); + } + if(foeiContext==null) { + throw new NullPointerException("FoeiContext may not be null."); + } + this.runnable=runnable; + this.foeiContext=foeiContext; + } + + /** + * Call all EventThreadListeners + */ + public void run() { + for(EventThreadListener eth:foeiContext.getEventExecutorManager().getEventThreadListeners()) { + eth.startThread(foeiContext); + } + // Executer the runnable object we wrapped. + // this is the runnable executor of the default thread pool in java 1.5 + runnable.run(); + for(EventThreadListener eth:foeiContext.getEventExecutorManager().getEventThreadListeners()) { + eth.stopThread(foeiContext); + } + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/core/impl/FoeiConfiguratorImpl.java b/src/com/idcanet/foei/core/impl/FoeiConfiguratorImpl.java new file mode 100644 index 0000000..44b4c63 --- /dev/null +++ b/src/com/idcanet/foei/core/impl/FoeiConfiguratorImpl.java @@ -0,0 +1,264 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.core.impl; + +import com.idcanet.foei.core.EventExecutorManager; +import com.idcanet.foei.core.EventThreadListener; +import com.idcanet.foei.core.FoeiConfigurator; +import com.idcanet.foei.core.FoeiContext; +import com.idcanet.foei.core.FoeiContextBuildingException; +import com.idcanet.foei.core.FoeiProcessManager; +import com.idcanet.foei.core.ObjectBindingsManager; +import com.idcanet.foei.utils.jndi.MemoryContextFactory; + +import java.util.Hashtable; +import java.util.Map; +import java.util.logging.Logger; + +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.spi.InitialContextFactory; + +/** + * Creates an default implemention an of FoeiContext. + * Which is config with the objects. + * + * + * @author Willem Cazander + * @version 1.0 Jan 20, 2006 + */ +public class FoeiConfiguratorImpl implements FoeiConfigurator { + + static private Logger logger = Logger.getLogger(FoeiConfiguratorImpl.class.getName()); + + /** + * Creates an FoeiContext + */ + public FoeiContext buildFoeiContext(Map properties) throws FoeiContextBuildingException { + + if(properties==null) { + throw new NullPointerException("properties may not be null."); + } + String name = getContextName(properties); + String rootPath = null; + Context objectContext = null; + EventExecutorManager eventExecutorManager = null; + FoeiProcessManager foeiProcessManager = null; + + try { + rootPath = getRootPath(properties); + objectContext = newContext(properties); + eventExecutorManager = newEventExecutorManager(properties); + foeiProcessManager = newFoeiProcessManager(properties); + loadEventThreadListeners(properties,eventExecutorManager); + } catch (Exception e) { + throw new FoeiContextBuildingException("Error while building childs objects:",e); + } + return new FoeiContextImpl(name,rootPath,objectContext,eventExecutorManager,properties,foeiProcessManager); + } + + /** + * Gets the contextName from the properties map. + * @param properties The properties map. + * @return Returns the contextName from the properties map. + */ + static public String getContextName(Map properties) { + String contextName = properties.get(FoeiConfigurator.CONTEXT_NAME); + if(contextName==null) { + throw new NullPointerException("contextName needs to be set in properties as: "+FoeiConfigurator.CONTEXT_NAME); + } + return contextName; + } + + /** + * Gets the root path from the properties Map. + * @param properties The properties map. + * @return Returns the rootpath from the properties map. + */ + static public String getRootPath(Map properties) { + String rootPath = properties.get(FoeiConfigurator.ROOT_PATH); + if(rootPath==null) { + throw new NullPointerException("rootPath needs to be set in properties as: "+FoeiConfigurator.ROOT_PATH); + } + return rootPath; + } + + + /** + * + * @param properties + * @return + * @throws ClassNotFoundException + * @throws InstantiationException + * @throws IllegalAccessException + */ + static public ObjectBindingsManager newObjectBindingsManager(Map properties) throws ClassNotFoundException,InstantiationException, IllegalAccessException { + String className = properties.get(FoeiConfigurator.OBJECT_BINDINGS_MANAGER); + if(className==null) { + return new ObjectBindingsManagerImpl(); + } + return (ObjectBindingsManager)Class.forName(className).newInstance(); + } + + /** + * + * @param properties + * @return + * @throws ClassNotFoundException + * @throws InstantiationException + * @throws IllegalAccessException + * @throws NamingException + */ + static public Context newContext(Map properties) throws ClassNotFoundException,InstantiationException, IllegalAccessException,NamingException { + String className = properties.get(FoeiConfigurator.OBJECT_CONTEXT_FACTORY); + if(className==null) { + return new MemoryContextFactory().getInitialContext(new Hashtable(properties)); + } + return ((InitialContextFactory)Class.forName(className).newInstance()).getInitialContext(new Hashtable(properties)); + } + + /** + * + * @param properties + * @return + * @throws ClassNotFoundException + * @throws InstantiationException + * @throws IllegalAccessException + */ + static public EventExecutorManager newEventExecutorManager(Map properties) throws ClassNotFoundException,InstantiationException, IllegalAccessException { + String className = properties.get(FoeiConfigurator.EVENT_EXECUTOR_MANAGER); + if(className==null) { + return new EventExecutorManagerImpl(); + } + return (EventExecutorManager)Class.forName(className).newInstance(); + } + + /** + * Loads and adds all the EventThreadListener. + * @param properties + * @param eventExecutorManager + * @throws Exception + */ + static public void loadEventThreadListeners(Map properties,EventExecutorManager eventExecutorManager) throws Exception { + String classNames = properties.get(FoeiConfigurator.EVENT_THREAD_LISTENERS); + if(classNames==null) { + logger.finer("No EventThreadListeners loading"); + return; + } + for(String className:classNames.split(",")) { + logger.finest("Loading class: "+className); + EventThreadListener eventThreadListener = (EventThreadListener)Class.forName(className).newInstance(); + eventExecutorManager.addEventThreadListener(eventThreadListener); + } + } + + /** + * Gets the Pool Core Size for the EventExecutor + * @param properties + * @return + * @throws NumberFormatException + */ + static public Integer getEventExecutorPoolCoreSize(Map properties) throws NumberFormatException { + String size = properties.get(FoeiConfigurator.EVENT_EXECUTOR_POOL_CORE_SIZE); + if(size==null) { + return 3; + } + return new Integer(size); + } + + /** + * Gets the Pool Max Size for the EventExecutor + * @param properties + * @return + * @throws NumberFormatException + */ + static public Integer getEventExecutorPoolMaxSize(Map properties) throws NumberFormatException { + String size = properties.get(FoeiConfigurator.EVENT_EXECUTOR_POOL_MAX_SIZE); + if(size==null) { + return 5; + } + return new Integer(size); + } + + /** + * Gets the Pool Keep Alive Time in second for the EventExecutor + * @param properties + * @return + * @throws NumberFormatException + */ + static public Integer getEventExecutorPoolKeepAlive(Map properties) throws NumberFormatException { + String size = properties.get(FoeiConfigurator.EVENT_EXECUTOR_POOL_KEEP_ALIVE); + if(size==null) { + return 180; + } + return new Integer(size); + } + + /** + * Creates an new EventExecutor class + * @param properties + * @return + * @throws ClassNotFoundException + */ + static public Class newEventExecutorClass(Map properties) throws ClassNotFoundException { + String className = properties.get(FoeiConfigurator.EVENT_EXECUTOR); + if(className==null) { + return EventExecutorImpl.class; + } + return Class.forName(className); + } + + /** + * Gets the X2O root tag + * @param properties + * @return The X2ORootTag + */ + static public String getX2ORootTag(Map properties) { + String rootTag = properties.get(FoeiConfigurator.X2O_ROOT_TAG); + if(rootTag==null) { + return "foei"; + } + return rootTag; + } + + /** + * + * @param properties + * @return + * @throws ClassNotFoundException + * @throws InstantiationException + * @throws IllegalAccessException + */ + static public FoeiProcessManager newFoeiProcessManager(Map properties) throws ClassNotFoundException,InstantiationException, IllegalAccessException { + String className = properties.get(FoeiConfigurator.FOEI_PROCESS_MANAGER); + if(className==null) { + return new FoeiProcessManagerImpl(); + } + return (FoeiProcessManager)Class.forName(className).newInstance(); + } + +} \ No newline at end of file diff --git a/src/com/idcanet/foei/core/impl/FoeiContextImpl.java b/src/com/idcanet/foei/core/impl/FoeiContextImpl.java new file mode 100644 index 0000000..bcb25e3 --- /dev/null +++ b/src/com/idcanet/foei/core/impl/FoeiContextImpl.java @@ -0,0 +1,149 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.core.impl; + +import com.idcanet.foei.core.EventExecutorManager; +import com.idcanet.foei.core.FoeiContext; +import com.idcanet.foei.core.FoeiProcessManager; + +import java.util.Map; +import javax.naming.Context; + +/** + * Defines the FoeiContext implemention. + * + * @see FoeiContext + * @author Willem Cazander + * @version 1.0 Jan 19, 2006 + */ +public class FoeiContextImpl implements FoeiContext +{ + /** The name of this Instance **/ + private String name = null; + + /** The root path of this instance **/ + private String rootPath = null; + + /** The FoeiContext where all objects are stored. **/ + private Context objectContext = null; + + /** The EventExecutorManager */ + private EventExecutorManager eventExecutorManager = null; + + /** The start properties */ + private Map startProperties = null; + + /** The FoeiProcessManager */ + private FoeiProcessManager foeiProcessManager = null; + + /** + * Creates an new FoeiContextImpl + * + * @param name + * @param rootPath + * @param objectBindingsManager + * @param objectContext + * @param eventExecutorManager + * @param startProperties + */ + public FoeiContextImpl(String name,String rootPath,Context objectContext,EventExecutorManager eventExecutorManager,Map startProperties,FoeiProcessManager foeiProcessManager) { + + if(name==null) { + throw new NullPointerException("name may not be null."); + } + if(rootPath==null) { + throw new NullPointerException("rootPath may not be null."); + } + if(objectContext==null) { + throw new NullPointerException("objectContext may not be null."); + } + if(eventExecutorManager==null) { + throw new NullPointerException("eventExecutorManager may not be null."); + } + if(foeiProcessManager==null) { + throw new NullPointerException("foeiProcessManager may not be null."); + } + + this.name=name; + this.rootPath=rootPath; + this.objectContext=objectContext; + this.eventExecutorManager=eventExecutorManager; + this.startProperties=startProperties; + this.foeiProcessManager=foeiProcessManager; + eventExecutorManager.start(this); + } + + /** + * @see FoeiContext#getName() + */ + public String getName() { + return name; + } + + /** + * @see FoeiContext#getRootPath() + */ + public String getRootPath() { + return rootPath; + } + + /** + * @see FoeiContext#getEventExecutorManager() + */ + public EventExecutorManager getEventExecutorManager() { + return eventExecutorManager; + } + + /** + * @see FoeiContext#getEventObjectContext() + */ + public Context getEventObjectContext() { + return objectContext; + } + + /** + * @see FoeiContext#getStartProperties() + */ + public Map getStartProperties() { + return startProperties; + } + + /** + * @see FoeiContext#destroy() + */ + public void destroy() { + getEventExecutorManager().stop(this); + } + + /** + * Gets the FoeiProcessManager + * @return Returns the FoeiProcessManager + */ + public FoeiProcessManager getFoeiProcessManager() { + return foeiProcessManager; + } +} diff --git a/src/com/idcanet/foei/core/impl/FoeiEventBindingRuleHandler.java b/src/com/idcanet/foei/core/impl/FoeiEventBindingRuleHandler.java new file mode 100644 index 0000000..a6e1194 --- /dev/null +++ b/src/com/idcanet/foei/core/impl/FoeiEventBindingRuleHandler.java @@ -0,0 +1,88 @@ + + +package com.idcanet.foei.core.impl; + +import com.idcanet.foei.event.EventInput; +import com.idcanet.foei.event.EventOutput; +import com.idcanet.foei.event.EventStep; +import com.idcanet.foei.event.EventStepController; +import com.idcanet.x4o.eld.BindingRuleHandler; +import com.idcanet.x4o.element.Element; + +import java.util.Map; + +/** + * + * MM maybe move this class + * + * @author Willem Cazander + * @version 1.0 Feb 24, 2006 + */ +public class FoeiEventBindingRuleHandler implements BindingRuleHandler { + + /** + * + * @param parameters + */ + public void setParameters(Map parameters) { + + } + + /** + * + * @param object1 + * @param object2 + * @return + */ + public boolean canBind(Element element) { + Object parent = element.getParent().getElementObject(); + Object child = element.getElementObject(); + + Object object1 = parent; + Object object2 = child; // is correct ?? + if(object1==null) { + throw new NullPointerException("object1 may not be null."); + } + if(object2==null) { + throw new NullPointerException("object2 may not be null."); + } + if(object1 instanceof EventInput) { + if(object2 instanceof EventOutput) { + return true; + } + } + if(object1 instanceof EventOutput) { + if(object2 instanceof EventInput) { + return true; + } + } + if(object1 instanceof EventStep) { + if(object2 instanceof EventStepController) { + return true; + } + } + if(object1 instanceof EventStepController) { + if(object2 instanceof EventStep) { + return true; + } + } + return false; + } + + /** + * + * @param object1 + * @param object2 + * @throws ClassCastException + */ + public void doBind(Element element) throws Exception { + Object parent = element.getParent().getElementObject(); + Object child = element.getElementObject(); + if(parent==null) { + throw new NullPointerException("object1 may not be null."); + } + if(child==null) { + throw new NullPointerException("object2 may not be null."); + } + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/core/impl/FoeiProcessImpl.java b/src/com/idcanet/foei/core/impl/FoeiProcessImpl.java new file mode 100644 index 0000000..a92ed4f --- /dev/null +++ b/src/com/idcanet/foei/core/impl/FoeiProcessImpl.java @@ -0,0 +1,187 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.core.impl; + +import com.idcanet.foei.core.FoeiContext; +import com.idcanet.foei.core.FoeiProcess; +import com.idcanet.foei.core.ObjectBindingsManager; +import com.idcanet.foei.event.EventPort; + +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.naming.Context; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameNotFoundException; +import javax.naming.NamingException; + +/** + * Defines the default FoeiProcess implementation + * + * @author Willem Cazander + * @version 1.0 Mar 2, 2006 + */ +public class FoeiProcessImpl implements FoeiProcess { + + /** The FoeiContext */ + private FoeiContext foeiContext = null; + /** The Logger */ + private Logger logger = null; + /** The name */ + private String name = null; + /** The eventObjectContext */ + private Context eventObjectContext = null; + /** The ObjectBindingsManager */ + private ObjectBindingsManager objectBindingsManager = null; + + public FoeiProcessImpl(String name,FoeiContext foeiContext,Context eventObjectContext,ObjectBindingsManager objectBindingsManager) { + logger = Logger.getLogger(FoeiProcessImpl.class.getName()); + this.name=name; + this.foeiContext=foeiContext; + this.eventObjectContext=eventObjectContext; + this.objectBindingsManager=objectBindingsManager; + logger.info("Creating FoeiProcess: "+getName()); + } + + // ========= FoeiProcess + + /** + * @see com.idcanet.foei.core.FoeiProcess#getName() + */ + public String getName() { + return name; + } + + /** + * @see com.idcanet.foei.core.FoeiProcess#getEventObjectContext() + */ + public Context getEventObjectContext() { + return eventObjectContext; + } + + /** + * @see com.idcanet.foei.core.FoeiProcess#getObjectBindingsManager() + */ + public ObjectBindingsManager getObjectBindingsManager() { + return objectBindingsManager; + } + + /** + * @see com.idcanet.foei.core.FoeiProcess#destroy() + */ + public void destroy() { + logger.info("Destroying FoeiProcess: "+getName()); + } + + /** + * @see com.idcanet.foei.core.FoeiProcess#getFoeiContext() + */ + public FoeiContext getFoeiContext() { + return foeiContext; + } + + // ================== EventPortExecutor + + /** + * @see com.idcanet.foei.core.EventPortExecutor#executeEvent(com.idcanet.foei.event.EventPort, java.lang.Object) + */ + public void executeEvent(EventPort eventPort, Object eventObject) { + getFoeiContext().getEventExecutorManager().executeEvent(eventPort,eventObject); + } + + // ============= ObjectContextManager + + /** + * @see com.idcanet.foei.core.ObjectContextManager#addEventObject(com.idcanet.foei.event.EventObject) + */ + public void addEventObject(Object eventObject,String id) { + try { + getEventObjectContext().bind(id,eventObject); + } catch (NameAlreadyBoundException nabe) { + logger.log(Level.WARNING,"NameAlreadyBoundException: "+nabe.getMessage(),nabe); + } catch (NamingException ne) { + logger.log(Level.WARNING,"NamingException: "+ne.getMessage(),ne); + } + } + + /** + * @see com.idcanet.foei.core.ObjectContextManager#getEventObject(java.lang.String) + */ + public Object getEventObject(String id) { + try { + return getEventObjectContext().lookup(id); + } catch (NamingException ne) { + logger.log(Level.WARNING,"NamingException: "+ne.getMessage(),ne); + } + return null; + } + + /** + * @see com.idcanet.foei.core.ObjectContextManager#removeEventObject(com.idcanet.foei.event.EventObject) + */ + public void removeEventObject(String id) { + try { + getEventObjectContext().unbind(id); + } catch (NameNotFoundException nnfe) { + logger.log(Level.WARNING,"NamingNotFoundException: "+nnfe.getMessage(),nnfe); + } catch (NamingException ne) { + logger.log(Level.WARNING,"NamingException: "+ne.getMessage(),ne); + } + } + + + // ============ ObjectBindingsManager + + /** + * @see com.idcanet.foei.core.ObjectBindingsManager#addBinding(com.idcanet.foei.event.EventPort, com.idcanet.foei.event.EventPort) + */ + public void addBinding(EventPort outputPort, EventPort inputPort) { + getObjectBindingsManager().addBinding(outputPort,inputPort); + } + + /** + * @see com.idcanet.foei.core.ObjectBindingsManager#getBindings(com.idcanet.foei.event.EventPort) + */ + public List getBindings(EventPort eventPort) { + return getObjectBindingsManager().getBindings(eventPort); + } + + /** + * @see com.idcanet.foei.core.ObjectBindingsManager#getBindingsAsXML() + */ + public String getBindingsAsXML() { + return getObjectBindingsManager().getBindingsAsXML(); + } + + /** + * @see com.idcanet.foei.core.ObjectBindingsManager#removeBinding(com.idcanet.foei.event.EventPort, com.idcanet.foei.event.EventPort) + */ + public void removeBinding(EventPort inputPort, EventPort outputPort) { + getObjectBindingsManager().removeBinding(inputPort,outputPort); + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/core/impl/FoeiProcessManagerImpl.java b/src/com/idcanet/foei/core/impl/FoeiProcessManagerImpl.java new file mode 100644 index 0000000..1c5bc89 --- /dev/null +++ b/src/com/idcanet/foei/core/impl/FoeiProcessManagerImpl.java @@ -0,0 +1,125 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.core.impl; + +import com.idcanet.foei.core.FoeiContext; +import com.idcanet.foei.core.FoeiProcess; +import com.idcanet.foei.core.FoeiProcessManager; +import com.idcanet.foei.core.ObjectBindingsManager; + +import java.util.Collection; +import java.util.HashMap; + +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.naming.Context; + +/** + * Defines the default FoeiProcessManager implementation + * + * @author Willem Cazander + * @version 1.0 Mar 2, 2006 + */ +public class FoeiProcessManagerImpl implements FoeiProcessManager { + + /** Stores all foeiProcesses */ + private Map foeiProcesses = null; + /** The logger to log to. */ + private Logger logger = null; + + /** + * Creates an FoeiProcessManagerImpl + */ + public FoeiProcessManagerImpl() { + logger = Logger.getLogger(FoeiProcessManagerImpl.class.getName()); + foeiProcesses = new HashMap(5); + } + + /** + * @see com.idcanet.foei.core.FoeiProcessManager#createFoeiProcess(java.lang.String, FoeiContext) + */ + public FoeiProcess createFoeiProcess(String name,FoeiContext foeiContext) { + if(name==null) { + throw new NullPointerException("name may not be null."); + } + if(foeiContext==null) { + throw new NullPointerException("foeiContext may not be null."); + } + try { + Context c = foeiContext.getEventObjectContext().createSubcontext(name); + ObjectBindingsManager objectBindingsManager = FoeiConfiguratorImpl.newObjectBindingsManager(foeiContext.getStartProperties()); + FoeiProcess fp = new FoeiProcessImpl(name,foeiContext,c,objectBindingsManager); + synchronized (foeiProcesses) { + foeiProcesses.put(fp.getName(),fp); + } + logger.finer("FoeiProcess created and added total processes: "+foeiProcesses.size()); + return fp; + } catch (Exception e) { + logger.log(Level.WARNING,"Error whiile creating FoeiProcess: "+e.getMessage(),e); + return null; + } + } + + /** + * @see com.idcanet.foei.core.FoeiProcessManager#destroyFoeiProcess(java.lang.String) + */ + public void destroyFoeiProcess(String name) { + FoeiProcess p = getFoeiProcess(name); + if(p==null) { + throw new NullPointerException("No FoeiProcess found with id: "+name); + } + p.destroy(); + synchronized (foeiProcesses) { + foeiProcesses.remove(p.getName()); + } + logger.finer("FoeiProcess destroyed total processes: "+foeiProcesses.size()); + try { + p.getFoeiContext().getEventObjectContext().destroySubcontext(p.getName()); + } catch (Exception e) { + logger.log(Level.WARNING,"Error while removing process context from foei context; "+e.getMessage(),e); + } + } + + /** + * @see com.idcanet.foei.core.FoeiProcessManager#getFoeiProcess(java.lang.String) + */ + public FoeiProcess getFoeiProcess(String name) { + if(name==null) { + throw new NullPointerException("name may not be null."); + } + return foeiProcesses.get(name); + } + + /** + * @see com.idcanet.foei.core.FoeiProcessManager#getFoeiProcesses() + */ + public Collection getFoeiProcesses() { + return foeiProcesses.values(); + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/core/impl/FoeiProcessRunnableWrapper.java b/src/com/idcanet/foei/core/impl/FoeiProcessRunnableWrapper.java new file mode 100644 index 0000000..cb88570 --- /dev/null +++ b/src/com/idcanet/foei/core/impl/FoeiProcessRunnableWrapper.java @@ -0,0 +1,70 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.core.impl; + +import com.idcanet.foei.core.FoeiProcess; +import com.idcanet.foei.core.FoeiProcessFactory; + +/** + * Wraps an Runnable object so it binds the FoeiProcess before running + * and unbinds it also. + * + * @author Willem Cazander + * @version 1.0 Mar 3, 2006 + */ +public class FoeiProcessRunnableWrapper implements Runnable { + + /** The wrapped runnable object. */ + private Runnable runnable = null; + /** The FoeiProcess for this Runnable. */ + private FoeiProcess foeiProcess = null; + + /** + * creates an FoeiProcessRunnableWrapper + * @param runnable + * @param foeiProcess + */ + public FoeiProcessRunnableWrapper(Runnable runnable,FoeiProcess foeiProcess) { + if(runnable==null) { + throw new NullPointerException("runnable may not be null."); + } + if(foeiProcess==null) { + throw new NullPointerException("FoeiProcess may not be null."); + } + this.runnable=runnable; + this.foeiProcess=foeiProcess; + } + + /** + * Binds and unbinds the FoeiProcess and call the runnalbe run method. + */ + public void run() { + FoeiProcessFactory.bindFoeiProcess(foeiProcess); + runnable.run(); + FoeiProcessFactory.unbindFoeiProcess(); + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/core/impl/ObjectBindingsManagerImpl.java b/src/com/idcanet/foei/core/impl/ObjectBindingsManagerImpl.java new file mode 100644 index 0000000..e6e09dc --- /dev/null +++ b/src/com/idcanet/foei/core/impl/ObjectBindingsManagerImpl.java @@ -0,0 +1,179 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.core.impl; + +import com.idcanet.foei.core.ObjectBindingsManager; +import com.idcanet.foei.event.EventPort; +import com.idcanet.foei.event.EventPortType; + +import java.util.HashMap; +import java.util.Map; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +/** + * Defines the ObjectBindingsManager implamentation. + * + * @author Willem Cazander + * @version 1.0 20/04/2005 + */ +public class ObjectBindingsManagerImpl implements ObjectBindingsManager +{ + /** */ + private Map> bindingsOutput = null; + /** Works like: eventPort(input) -> List (EventPorts(output) */ + private Map> bindingsInput = null; + /** The logger to log to. */ + private Logger logger = null; + + /** + * Creates the defaults implementation of the ObjectBindingsManager.
+ * inits the logger and de input and output Map mappings. + */ + public ObjectBindingsManagerImpl() { + logger = Logger.getLogger(ObjectBindingsManagerImpl.class.getName()); + bindingsOutput = new HashMap>(50); + bindingsInput = new HashMap>(50); + logger.finer("BindingsManager Created"); + } + + /** + * + * @see ObjectBindingsManager#addBinding(EventPort, EventPort) + */ + public void addBinding(EventPort outputPort,EventPort inputPort) { + if(inputPort==null) { + throw new NullPointerException("inputPort may not be null."); + } + if(inputPort.getEventPortType()!=EventPortType.input) { + throw new IllegalArgumentException("inputPort needs to be input type."); + } + if(outputPort==null) { + throw new NullPointerException("outputPort may not be null."); + } + if(outputPort.getEventPortType()!=EventPortType.output) { + throw new IllegalArgumentException("inputPort needs to be ouput type."); + } + + List inputPorts = bindingsInput.get(inputPort); + List outputPorts = bindingsOutput.get(outputPort); + if(inputPorts==null) { + inputPorts = new ArrayList(5); + bindingsInput.put(inputPort,inputPorts); + } + if(outputPorts==null) { + outputPorts = new ArrayList(5); + bindingsOutput.put(outputPort,outputPorts); + } + + // disables to bind twice + if(inputPorts.contains(outputPort) || outputPorts.contains(inputPort) ) { + throw new IllegalArgumentException("inputPort is already bind to outputPort"); + } + inputPorts.add(outputPort); + outputPorts.add(inputPort); + logger.fine("Bind completed: "+inputPort.getEventObject()+":"+inputPort.getName()+" to "+outputPort.getEventObject()+":"+outputPort.getName()); + } + + /** + * + * @see ObjectBindingsManager#removeBinding(EventPort, EventPort) + */ + public void removeBinding(EventPort inputPort,EventPort outputPort) { + if(inputPort==null) { + throw new NullPointerException("inputPort may not be null."); + } + if(inputPort.getEventPortType()!=EventPortType.input) { + throw new IllegalArgumentException("inputPort needs to be input type."); + } + if(outputPort==null) { + throw new NullPointerException("outputPort may not be null."); + } + if(outputPort.getEventPortType()!=EventPortType.output) { + throw new IllegalArgumentException("inputPort needs to be ouput type."); + } + + List inputPorts = bindingsInput.get(inputPort); + List outputPorts = bindingsOutput.get(outputPort); + + if(inputPorts==null || outputPorts==null) { + throw new IllegalArgumentException("Can not remove not binded ports."); + } + + inputPorts.remove(outputPort); + outputPorts.remove(inputPort); + + if(inputPorts.isEmpty()) { + bindingsInput.remove(inputPort); + } + if(outputPorts.isEmpty()) { + bindingsOutput.remove(outputPort); + } + logger.fine("Bind removed: "+inputPort.getEventObject()+":"+inputPort.getName()+" to "+outputPort.getEventObject()+":"+outputPort.getName()); + } + + /** + * Gets the bindings of an EventPort + * @param eventPort The EventPort to retreive the bindings. + * @return Returns an List of the binded EventPorts + */ + public List getBindings(EventPort eventPort) { + if(eventPort==null) { + throw new NullPointerException("eventPort may not be null."); + } + List result = new ArrayList(0); + List inputPorts = bindingsInput.get(eventPort); + List outputPorts = bindingsOutput.get(eventPort); + if(inputPorts!=null) { + result.addAll(inputPorts); + } + if(outputPorts!=null) { + result.addAll(outputPorts); + } + return result; + } + + /** + * Returns the dotty xml bindings + */ + public String getBindingsAsXML() { + StringBuffer result = new StringBuffer(); + result.append("\n"); + result.append("\n"); + for(EventPort port:bindingsOutput.keySet()) { + for(EventPort b:getBindings(port)) { + result.append("\n"); + + } + } + result.append(""); + return result.toString(); + } +} diff --git a/src/com/idcanet/foei/core/impl/X2OExecutorImpl.java b/src/com/idcanet/foei/core/impl/X2OExecutorImpl.java new file mode 100644 index 0000000..b205c05 --- /dev/null +++ b/src/com/idcanet/foei/core/impl/X2OExecutorImpl.java @@ -0,0 +1,150 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.core.impl; + +import com.idcanet.foei.core.FoeiProcess; +import com.idcanet.foei.core.FoeiProcessFactory; +import com.idcanet.foei.core.X2OExecutor; +import com.idcanet.x4o.core.X4OParser; + +import java.io.InputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * The default X2OExecutor implemention + * + * @author Willem Cazander + * @version 1.0 Feb 24, 2006 + * + */ +public class X2OExecutorImpl implements X2OExecutor { + + private String parseFileName = null; + private InputStream parseInputStream = null; + private String parseXml = null; + private boolean debug = false; + private boolean ready = false; + private Logger logger = null; + + /** + * Constructs an X2OExecutorImpl + */ + public X2OExecutorImpl() { + logger = Logger.getLogger(X2OExecutorImpl.class.getName()); + } + + + /** + * @see java.lang.Runnable#run() + */ + public void run() { + try { + + // config parser + FoeiProcess foeiProcess = FoeiProcessFactory.getFoeiProcess(); + X4OParser parser = new X4OParser(FoeiConfiguratorImpl.getX2ORootTag(foeiProcess.getFoeiContext().getStartProperties()),"foei"); + parser.setDebug(debug); + parser.getParsingContext().getProperties().putAll(foeiProcess.getFoeiContext().getStartProperties()); + + logger.info("Executing X2O Parsing."); + + if(parseFileName!=null) { + try { + logger.finer("Parsing File: "+parseFileName); + parser.parseFile(parseFileName); + } catch (Exception e) { + logger.log(Level.SEVERE,"Error while loading config file:"+e.getMessage(),e); + } + } + + if(parseInputStream!=null) { + try { + logger.finer("Parsing InputStream"); + parser.parse(parseInputStream); + } catch (Exception e) { + logger.log(Level.SEVERE,"Error while loading inputStream:"+e.getMessage(),e); + } + } + + if(parseXml!=null) { + try { + logger.finer("Parsing XML"); + parser.parseXml(parseXml); + } catch (Exception e) { + logger.log(Level.SEVERE,"Error while loading xml:"+e.getMessage(),e); + } + } + } catch (Throwable t) { + logger.log(Level.WARNING,"Error in X2O thread: "+t.getMessage(),t); + } finally { + ready = true; + } + } + + /** + * @see com.idcanet.foei.core.X2OExecutor#isReady() + */ + public boolean isReady() { + return ready; + } + + /** + * @see com.idcanet.foei.core.X2OExecutor#getDebug() + */ + public boolean getDebug() { + return debug; + } + + /** + * @see com.idcanet.foei.core.X2OExecutor#setDebug(boolean) + */ + public void setDebug(boolean debug) { + this.debug=debug; + } + + /** + * @see com.idcanet.foei.core.X2OExecutor#setFileName(java.lang.String) + */ + public void setFileName(String fileName) { + parseFileName=fileName; + } + + /** + * @see com.idcanet.foei.core.X2OExecutor#setInputStream(java.io.InputStream) + */ + public void setInputStream(InputStream inputStream) { + parseInputStream=inputStream; + } + + /** + * @see com.idcanet.foei.core.X2OExecutor#setXml(java.lang.String) + */ + public void setXml(String xml) { + parseXml=xml; + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/core/impl/package.html b/src/com/idcanet/foei/core/impl/package.html new file mode 100644 index 0000000..fed3fbf --- /dev/null +++ b/src/com/idcanet/foei/core/impl/package.html @@ -0,0 +1,58 @@ + + + + + + +Defines the Foei Event Core Implemention.
+ +Some classes are build to be used for overriding classes so
+they have method to make live easer.
+ + + +

Related Documentation

+ +None. + + + + + \ No newline at end of file diff --git a/src/com/idcanet/foei/core/x4o/BindAttributeHandler.java b/src/com/idcanet/foei/core/x4o/BindAttributeHandler.java new file mode 100644 index 0000000..53593bc --- /dev/null +++ b/src/com/idcanet/foei/core/x4o/BindAttributeHandler.java @@ -0,0 +1,94 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.core.x4o; + +import com.idcanet.foei.core.FoeiProcess; +import com.idcanet.foei.core.FoeiProcessFactory; +import com.idcanet.foei.event.EventInput; +import com.idcanet.foei.event.EventOutput; +import com.idcanet.foei.event.EventPort; +import com.idcanet.x4o.eld.GlobalParameterHandler; +import com.idcanet.x4o.element.Element; +import com.idcanet.x4o.element.ElementException; + +/** + * Handlers the "bind" attribute + * + * @author Willem Cazander + * @version 1.0 Apr 15, 2006 + */ +public class BindAttributeHandler implements GlobalParameterHandler { + + private String parameterName =null; + + /** + * @see com.idca.foei.xml.x2o.eld.GlobalParameterHandler#doParameter(java.lang.Object, java.lang.String) + */ + public void doParameter(Element element,String parameterValue) { + String[] port = parameterValue.split(":"); + if(port.length!=2) { + return; + } + try { + + EventInput in = (EventInput)element.getElementObject(); + if(in==null) { + throw new ElementException("Could not find EventObject from inputID"); + } + EventOutput out = (EventOutput)element.getParent().getElementObject(); + if(out==null) { + throw new ElementException("Could not find EventObject from outputID"); + } + EventPort inputEventPort = in.getInputPort(port[1]); + EventPort outputEventPort = out.getOutputPort(port[0]); + + FoeiProcess foei = FoeiProcessFactory.getFoeiProcess(); + + if(inputEventPort==null) { + throw new ElementException("Could not find EventPort from inputPort"); + } + if(outputEventPort==null) { + throw new ElementException("Could not find EventPort from outputPort"); + } + foei.addBinding(outputEventPort,inputEventPort); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * @see com.idca.foei.xml.x2o.eld.GlobalParameterHandler#getParameterName() + */ + public String getParameterName() { + return parameterName; + } + + public void setParameterName(String parameterName) { + this.parameterName=parameterName; + } +} diff --git a/src/com/idcanet/foei/core/x4o/EventStepBindRuleHandler.java b/src/com/idcanet/foei/core/x4o/EventStepBindRuleHandler.java new file mode 100644 index 0000000..4b4ef52 --- /dev/null +++ b/src/com/idcanet/foei/core/x4o/EventStepBindRuleHandler.java @@ -0,0 +1,76 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.core.x4o; + +import com.idcanet.foei.event.EventStep; +import com.idcanet.foei.event.EventStepController; +import com.idcanet.x4o.eld.BindingRuleHandler; +import com.idcanet.x4o.element.Element; + +import java.util.Map; + +/** + * + * + * @author Willem Cazander + * @version 1.0 Apr 16, 2006 + */ +public class EventStepBindRuleHandler implements BindingRuleHandler { + + private Map parameters = null; + + /** + * @see com.idca.foei.xml.x2o.eld.BindingRuleHandler#canBind(java.lang.Object, java.lang.Object) + */ + public boolean canBind(Element element) { + Object parent = element.getParent().getElementObject(); + Object child = element.getElementObject(); + if(!(parent instanceof EventStepController)) { + return false; + } + if(!(child instanceof EventStep)) { + return false; + } + return true; + } + + /** + * @see com.idca.foei.xml.x2o.eld.BindingRuleHandler#doBind(java.lang.Object, java.lang.Object) + */ + public void doBind(Element element) throws Exception { + Object parent = element.getParent().getElementObject(); + Object child = element.getElementObject(); + ((EventStepController)parent).addEventStep((EventStep)child); + } + + /** + * @see com.idca.foei.xml.x2o.eld.BindingRuleHandler#setParameters(java.util.Map) + */ + public void setParameters(Map parameters) { + this.parameters=parameters; + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/core/x4o/IdAttributeHandler.java b/src/com/idcanet/foei/core/x4o/IdAttributeHandler.java new file mode 100644 index 0000000..4442cf6 --- /dev/null +++ b/src/com/idcanet/foei/core/x4o/IdAttributeHandler.java @@ -0,0 +1,67 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.core.x4o; + +import com.idcanet.foei.core.FoeiProcess; +import com.idcanet.foei.core.FoeiProcessFactory; +import com.idcanet.x4o.eld.GlobalParameterHandler; +import com.idcanet.x4o.element.Element; + +/** + * Handles the id + * + * @author Willem Cazander + * @version 1.0 Jul 8, 2006 + */ +public class IdAttributeHandler implements GlobalParameterHandler { + + private String parameterName =null; + + /** + * @see com.idca.foei.xml.x2o.eld.GlobalParameterHandler#doParameter(java.lang.Object, java.lang.String) + */ + public void doParameter(Element element,String parameterValue) { + // add to objext context + if(element.getElementObject()==null | "".equals(parameterValue)) { + parameterValue= "auto."+Integer.toHexString(element.getElementObject().hashCode()); + //logger.finest("Generated auto id: "+parameterValue); + } + FoeiProcess process = FoeiProcessFactory.getFoeiProcess(); + process.addEventObject(element.getElementObject(),parameterValue); + } + + /** + * @see com.idca.foei.xml.x2o.eld.GlobalParameterHandler#getParameterName() + */ + public String getParameterName() { + return parameterName; + } + + public void setParameterName(String parameterName) { + this.parameterName=parameterName; + } +} diff --git a/src/com/idcanet/foei/core/x4o/ObjectBindingElement.java b/src/com/idcanet/foei/core/x4o/ObjectBindingElement.java new file mode 100644 index 0000000..f34757b --- /dev/null +++ b/src/com/idcanet/foei/core/x4o/ObjectBindingElement.java @@ -0,0 +1,150 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.core.x4o; + +import com.idcanet.foei.core.FoeiProcess; +import com.idcanet.foei.core.FoeiProcessFactory; +import com.idcanet.foei.event.EventInput; +import com.idcanet.foei.event.EventOutput; +import com.idcanet.foei.event.EventPort; +import com.idcanet.x4o.element.AbstractElement; +import com.idcanet.x4o.element.ElementException; + +import org.xml.sax.Attributes; + +/** + * + * + * @author Willem Cazander + * @version 1.0 Mar 2, 2006 + */ +public class ObjectBindingElement extends AbstractElement { + + /** The Object which is configed */ + //private Object parentObject = null; + //private Object childObject = null; + + private String outputID = null; + private String outputPort = null; + private String inputID = null; + private String inputPort = null; + + /** + * Do the element + */ + public void doElementStart(Attributes attributes) throws ElementException { + + outputID = attributes.getValue("outputID"); + outputPort = attributes.getValue("outputPort"); + inputID = attributes.getValue("inputID"); + inputPort = attributes.getValue("inputPort"); + + FoeiProcess foei = FoeiProcessFactory.getFoeiProcess(); + + Object in = foei.getEventObject(inputID); + if(in==null) { + throw new ElementException("Could not find EventObject from inputID"); + } + Object out = foei.getEventObject(outputID); + if(out==null) { + throw new ElementException("Could not find EventObject from outputID"); + } + EventPort inputEventPort = ((EventInput)in).getInputPort(inputPort); + EventPort outputEventPort = ((EventOutput)out).getOutputPort(outputPort); + if(inputEventPort==null) { + throw new ElementException("Could not find EventPort from inputPort"); + } + if(outputEventPort==null) { + throw new ElementException("Could not find EventPort from outputPort"); + } + foei.addBinding(outputEventPort,inputEventPort); + + + /* + if(outputID==null) { + //outputID = foei.getObjectConfigurator().getParameter(parentObject,"id").toString(); + } + if(outputPort==null) { + if(parentObject instanceof EventOutput) { + EventOutput eventOutput = (EventOutput)parentObject; + if(eventOutput.getOutputPorts().size()>0) { + EventPort port = (EventPort)eventOutput.getOutputPorts().get(0); + outputPort = port.getName(); + } else { + // no output ports + throw new ElementException("parentObject(EventOutput) is no output ports defined"); + } + } else { + // np EventOutput .. + throw new ElementException("parentObject: "+parentObject+" is not an EventOutput"); + } + } + */ + } + + // HACK routines + /* + public String getOutputID() { + return outputID; + } + public String getOutputPort() { + return outputPort; + } + */ + + public void doElementEnd() { + /* + FoeiProcess foei = FoeiProcessFactory.getFoeiProcess(); + if(inputID!=null & inputPort!=null & outputID!=null & outputPort!=null) { + // Add binding + foei.addBinding() + foeiInstance.getObjectBindingsManager().addBinding(outputID,outputPort,inputID,inputPort); + } else { + System.err.println("Coudn't addbinding: inID="+inputID+" inPort="+inputPort+" outID="+outputID+" outPort="+outputPort); + } + */ + } + + + //------------------ ElementObject + + /** + * Get the object this elements configs. + * @return The object this Element controlles + */ + /* + public Object getElementObject() { + return parentObject; + //return object; + } + + public void setElementObject(Object object) { + // TODO: this is an quich hack see FoeiTagHandler + //this.object=object; + } + */ +} \ No newline at end of file diff --git a/src/com/idcanet/foei/core/x4o/SetParameterElement.java b/src/com/idcanet/foei/core/x4o/SetParameterElement.java new file mode 100644 index 0000000..c9d976c --- /dev/null +++ b/src/com/idcanet/foei/core/x4o/SetParameterElement.java @@ -0,0 +1,88 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.core.x4o; + + +import org.xml.sax.Attributes; + +import com.idcanet.x4o.element.AbstractElement; +import com.idcanet.x4o.element.ElementException; + +/** + * + * + * @author Willem Cazander + * @version 1.0 Mar 2, 2006 + */ +public class SetParameterElement extends AbstractElement { + /** The Object which is configed */ + private Object object = null; + + private Object eventObject = null; + private String parameterName = null; + private Object parameterValue = null; + + public SetParameterElement() { + } + + /** + * Do the element + */ + public void doElementStart(Attributes attributes) throws ElementException + { + // the EventObject for the parent element is also this its elementObject. + Object o = getParent().getElementObject(); + /* + if(!(o instanceof EventObject)) { + throw new ElementException("parent ElementObject is not EventObject"); + } + eventObject = (EventObject)o; + */ + parameterName = attributes.getValue("name"); + parameterValue = attributes.getValue("value"); + } + + public void doElementEnd() + { + + } + + + //------------------ ElementObject + + /** + * Get the object this elements configs. + * @return The object this Element controlles + */ + public Object getElementObject() { + return object; + } + + public void setElementObject(Object object) { + this.object=object; + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/core/x4o/package.html b/src/com/idcanet/foei/core/x4o/package.html new file mode 100644 index 0000000..0117f6e --- /dev/null +++ b/src/com/idcanet/foei/core/x4o/package.html @@ -0,0 +1,55 @@ + + + + + + +Special Element object for foei xml.
+ + + +

Related Documentation

+ +None. + + + + + \ No newline at end of file diff --git a/src/com/idcanet/foei/event/annotations/SetEventPort.java b/src/com/idcanet/foei/event/annotations/SetEventPort.java new file mode 100644 index 0000000..b352b42 --- /dev/null +++ b/src/com/idcanet/foei/event/annotations/SetEventPort.java @@ -0,0 +1,70 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.event.annotations; + +import com.idcanet.foei.event.EventPortType; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Defines an input EventPort + * + * @author Willem Cazander + * @version 1.0 Jan 20, 2006 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface SetEventPort { + + /** + * + * @return + */ + EventPortType type(); + + /** + * Gets the name of the input EventPort + * @return Returns the name of the input EventPort + */ + String name(); + + /** + * Gets the objectType of the input EventPort + * it defaults to Object.class but is lookuped in the annotated method. + * @return Returns the objectType of the input EventPort + */ + Class objectType() default Object.class; + + /** + * + * @return + */ + String immediate() default "null"; +} \ No newline at end of file diff --git a/src/com/idcanet/foei/event/annotations/SetEventPorts.java b/src/com/idcanet/foei/event/annotations/SetEventPorts.java new file mode 100644 index 0000000..8fcc109 --- /dev/null +++ b/src/com/idcanet/foei/event/annotations/SetEventPorts.java @@ -0,0 +1,49 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.event.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Defines an output EventPort + * + * @author Willem Cazander + * @version 1.0 Jan 20, 2006 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface SetEventPorts { + + /** + * An array of SetEventPort annotations + * @return Returns an array of SetEventPort annotations + */ + SetEventPort[] ports(); +} \ No newline at end of file diff --git a/src/com/idcanet/foei/server/config/FoeiConfigContext.java b/src/com/idcanet/foei/server/config/FoeiConfigContext.java new file mode 100644 index 0000000..03de6a9 --- /dev/null +++ b/src/com/idcanet/foei/server/config/FoeiConfigContext.java @@ -0,0 +1,37 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.server.config; + +import java.util.Map; + +public class FoeiConfigContext { + + private String name = null; + private Map properties = null; + private Map processes = null; + +} \ No newline at end of file diff --git a/src/com/idcanet/foei/server/config/FoeiConfigParser.java b/src/com/idcanet/foei/server/config/FoeiConfigParser.java new file mode 100644 index 0000000..bd0352b --- /dev/null +++ b/src/com/idcanet/foei/server/config/FoeiConfigParser.java @@ -0,0 +1,70 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.server.config; + +import com.idca.foei.xml.AbstractXMLParser; +import com.idca.foei.xml.XMLDebugTagHandler; +import com.idca.foei.xml.XMLHandler; + +import java.io.IOException; +import java.io.InputStream; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.SAXException; + +/** + * Parses the foei-config.xml file + * + * + * @author Willem Cazander + * @version 1.0 Jun 23, 2006 + */ +public class FoeiConfigParser extends AbstractXMLParser { + + /** + * Parsesn the input stream as a X2O document + */ + public void parse(InputStream inputStream) throws ParserConfigurationException,SAXException,IOException { + XMLHandler handler = new XMLHandler(); + if(isDebug()) { + handler.addXMLTagHandler(new XMLDebugTagHandler("DEBUG")); + } + /* + X2OTagHandler xth = new X2OTagHandler(rootTag,parsingContext); + xth.setDebug(debug); + handler.addXMLTagHandler(xth); + */ + + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setNamespaceAware(true); + SAXParser saxParser = factory.newSAXParser(); + saxParser.parse(inputStream,handler); + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/server/config/FoeiContextXMLTagHandler.java b/src/com/idcanet/foei/server/config/FoeiContextXMLTagHandler.java new file mode 100644 index 0000000..7d9398c --- /dev/null +++ b/src/com/idcanet/foei/server/config/FoeiContextXMLTagHandler.java @@ -0,0 +1,65 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.server.config; + +import com.idca.foei.xml.AbstractXMLTagHandler; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +/** + * + * + * + * @author Willem Cazander + * @version 1.0 Jun 23, 2006 + */ +public class FoeiContextXMLTagHandler extends AbstractXMLTagHandler { + + + @Override + public void startElement(String nameSpace,String tag,String qName,Attributes attributes) throws SAXException { + + } + + @Override + public void endElement(String nameSpace,String tag,String qName) throws SAXException { + + } + + /** + * @see AbstractXMLTagHandler#characters(String) + */ + @Override + public void characters(String text) {/* + if(this.text==null) { + this.text=text; + } else { + this.text+=text; + } */ + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/server/config/package.html b/src/com/idcanet/foei/server/config/package.html new file mode 100644 index 0000000..bdf2d88 --- /dev/null +++ b/src/com/idcanet/foei/server/config/package.html @@ -0,0 +1,69 @@ + + + + + + +Provides some startup util classes for starting and config multipe Foei instances in a ServletContainer.
+ +

Package Specification

+ +We can access an FoeiContext here in the FoeiContextManager.
+Use with care !!
+
+To be sure of your code use something like:
+
+		FoeiContext foeiContext = FoeiContextManagerFactory.getFoeiContextManager().getFoeiContext("Test-Context");
+		FoeiContextFactory.bindFoeiContext(foeiContext);
+		// Do your stuff here.
+		//....
+		FoeiContextFactory.unbindFoeiContext();
+
+ + + +

Related Documentation

+ +None. + + + + + \ No newline at end of file diff --git a/src/com/idcanet/foei/server/startup/FoeiStartupListener.java b/src/com/idcanet/foei/server/startup/FoeiStartupListener.java new file mode 100644 index 0000000..b61a913 --- /dev/null +++ b/src/com/idcanet/foei/server/startup/FoeiStartupListener.java @@ -0,0 +1,107 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.server.startup; + +import com.idcanet.foei.core.FoeiConfigurator; +import com.idcanet.foei.core.FoeiContext; +import com.idcanet.foei.server.FoeiContextManager; +import com.idcanet.foei.server.FoeiContextManagerFactory; + +import java.io.InputStream; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +/** + * Helps to startup Foei in a J2EE context. + * + * Its creates the FoeiContextManager and builds FoeiContext for us. + * + * @author Willem Cazander + * @version 1.0 Jan 20, 2006 + */ +public class FoeiStartupListener implements ServletContextListener { + + /** The logger to log to. */ + private Logger logger = null; + + /** The key for in web.xml */ + static public final String FOEI_CONFIG_RESOURCES = "FOEI_CONFIG_RESOURCES"; + + /** + * Starts Foei + */ + public void contextInitialized(ServletContextEvent event) { + logger = Logger.getLogger(FoeiStartupListener.class.getName()); + + // Creates FoeiContextManager + FoeiContextManager foeiContextManager = new FoeiContextManager(); + FoeiContextManagerFactory.setFoeiContextManager(foeiContextManager); + + String resources = event.getServletContext().getInitParameter(FOEI_CONFIG_RESOURCES); + if(resources==null) { + logger.warning("No "+FOEI_CONFIG_RESOURCES+" defined in web.xml not starting foei."); + return; + } + + String[] resource = resources.split(","); + for(String className:resource) { + try { + InputStream foeiProperties = this.getClass().getResourceAsStream(className); + if(foeiProperties==null) { + logger.warning("Can't load: '"+className+"'"); + continue; + } + Properties properties = new Properties(); + properties.load(foeiProperties); + foeiProperties.close(); + properties.put(FoeiConfigurator.ROOT_PATH,event.getServletContext().getRealPath("/")); + foeiContextManager.createFoeiContext(properties); + + + } catch (Exception e) { + logger.log(Level.WARNING,"Error while starting FoeiContext: "+e.getMessage(),e); + } + } + } + + /** + * Stop Foei + */ + public void contextDestroyed(ServletContextEvent event) { + logger.info("Stopping Foei Contexts"); + try { + FoeiContextManagerFactory.getFoeiContextManager().destroyAll(); + } catch (Exception e) { + logger.log(Level.WARNING,"Error while shutdowning Foei: "+e.getMessage(),e); + } + } + +} \ No newline at end of file diff --git a/src/com/idcanet/foei/server/startup/package.html b/src/com/idcanet/foei/server/startup/package.html new file mode 100644 index 0000000..bdf2d88 --- /dev/null +++ b/src/com/idcanet/foei/server/startup/package.html @@ -0,0 +1,69 @@ + + + + + + +Provides some startup util classes for starting and config multipe Foei instances in a ServletContainer.
+ +

Package Specification

+ +We can access an FoeiContext here in the FoeiContextManager.
+Use with care !!
+
+To be sure of your code use something like:
+
+		FoeiContext foeiContext = FoeiContextManagerFactory.getFoeiContextManager().getFoeiContext("Test-Context");
+		FoeiContextFactory.bindFoeiContext(foeiContext);
+		// Do your stuff here.
+		//....
+		FoeiContextFactory.unbindFoeiContext();
+
+ + + +

Related Documentation

+ +None. + + + + + \ No newline at end of file diff --git a/src/com/idcanet/foei/utils/beans/BeanProperty.java b/src/com/idcanet/foei/utils/beans/BeanProperty.java new file mode 100644 index 0000000..ff03b37 --- /dev/null +++ b/src/com/idcanet/foei/utils/beans/BeanProperty.java @@ -0,0 +1,40 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.utils.beans; + +/** + * Gets ans Set properties of an java bean + * + * + * @author Willem Cazander + * @version 1.0 Jan 18, 2006 + */ +public class BeanProperty { + + + +} \ No newline at end of file diff --git a/src/com/idcanet/foei/utils/beans/BeanPropertyComparator.java b/src/com/idcanet/foei/utils/beans/BeanPropertyComparator.java new file mode 100644 index 0000000..b21b3c5 --- /dev/null +++ b/src/com/idcanet/foei/utils/beans/BeanPropertyComparator.java @@ -0,0 +1,174 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.utils.beans; + +import java.lang.Comparable; +import java.util.Comparator; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.commons.beanutils.BeanUtils; + +/** + * Compares a property of a java bean. + * The property should be Comparable. + * + * @author Willem Cazander + * @version 1.0 Jan 11, 2006 + */ +public class BeanPropertyComparator implements Comparator { + + /** The propery of the bean to compare. */ + private String property = null; + /** The logger to log to. */ + private Logger logger = null; + /** The ascending */ + private boolean ascending = true; + + /** + * The constructor inits the logger. + */ + public BeanPropertyComparator() { + logger = Logger.getLogger(BeanPropertyComparator.class.getName()); + } + + /** + * Creates an BeanPropertyComparator with an property + * @param property + */ + public BeanPropertyComparator(String property) { + this(); + setProperty(property); + } + + /** + * Creates an BeanPropertyComparator with an property + * @param property + */ + public BeanPropertyComparator(String property,boolean ascending) { + this(); + setProperty(property); + setAscending(ascending); + } + + /** + * Compares 2 objects by the propery + * @see Comparator#compare(T, T); + * @param o1 Object 1 + * @param o2 Object 2 + * @return the differce between the objects. + */ + public int compare(Object o1,Object o2) throws ClassCastException { + + Comparable c1 = getComparableProperty(o1); + Comparable c2 = getComparableProperty(o2); + + if(c1==null && c2==null) { + return 0; + } + if(c1==null) { + if(ascending) { + return 1; + } else { + return -1; + } + } + if(c2==null) { + if(ascending) { + return 1; + } else { + return -1; + } + } + + if(ascending) { + return c1.compareTo(c2); + } else { + return c2.compareTo(c1); + } + } + + /** + * Returns the Comparable property of the object. + * @param object + * @return + * @throws ClassCastException + */ + private Comparable getComparableProperty(Object object) throws ClassCastException { + + if(property==null) { + throw new IllegalStateException("property is not set."); + } + Object result = null; + try { + result = BeanUtils.getProperty(object,property); + } catch (Exception e) { + logger.log(Level.WARNING,"property:"+property+" is not an property of object: "+object.getClass().getName(),e); + } + try { + Comparable c = (Comparable)result; + return c; + } catch (ClassCastException e) { + logger.log(Level.WARNING,"property:"+property+" is not Comparable",e); + throw e; + } + } + + /** + * @return Returns the property. + */ + public String getProperty() { + return property; + } + + /** + * @param property The property to set. + */ + public void setProperty(String property) { + if(property==null) { + throw new NullPointerException("property may not be null"); + } + this.property = property; + logger.finest("property="+property); + } + + /** + * @return Returns the ascending. + */ + public boolean isAscending() { + return ascending; + } + + /** + * @param ascending The ascending to set. + */ + public void setAscending(boolean ascending) { + this.ascending = ascending; + logger.finest("ascending="+ascending); + } +} + diff --git a/src/com/idcanet/foei/utils/beans/NumberComparator.java b/src/com/idcanet/foei/utils/beans/NumberComparator.java new file mode 100644 index 0000000..947fa43 --- /dev/null +++ b/src/com/idcanet/foei/utils/beans/NumberComparator.java @@ -0,0 +1,95 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.utils.beans; + +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Comparator; +import java.util.Locale; + +/** + * + * + * @author Willem Cazander + * @version 1.0 Feb 9, 2006 + */ +public class NumberComparator implements Comparator { + + private Locale locale = null; + + /** + * @return Returns the locale. + */ + public Locale getLocale() { + return locale; + } + + /** + * @param locale The locale to set. + */ + public void setLocale(Locale locale) { + this.locale = locale; + } + + /** + * Compares two String as number. + * @param o1 + * @param o2 + * @return + * @see Comparator#compare(T, T) + */ + public int compare(Object o1, Object o2) { + Double d1 = getDoubleValue((String)o1,locale); + Double d2 = getDoubleValue((String)o2,locale); + return d1.compareTo(d2); + } + + /** + * Converts an String to an Number wich is converted to a Double + * @param test The String to parse. + * @param locale The locale of the numberFormat. + * @return An Double + */ + static public Double getDoubleValue(String text,Locale locale) { + try { + NumberFormat nf = NumberFormat.getInstance(locale); + Number n = nf.parse(text); + if(n instanceof Double) { + return (Double)n; + } + if(n instanceof Integer) { + return ((Integer)n).doubleValue(); + } + if(n instanceof Long) { + return ((Long)n).doubleValue(); + } + } catch(ParseException pe) { + } catch (NumberFormatException e) { + } + return 0.0; + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/utils/beans/package.html b/src/com/idcanet/foei/utils/beans/package.html new file mode 100644 index 0000000..547a56e --- /dev/null +++ b/src/com/idcanet/foei/utils/beans/package.html @@ -0,0 +1,61 @@ + + + + + + +Provides some handy classes for working with java beans.
+ +

Package Specification

+ +
    +
  • Full J2SE 5 compatible
  • +
  • Small package
  • +
+ + +

Related Documentation

+ +None. + + + + + \ No newline at end of file diff --git a/src/com/idcanet/foei/utils/jdbc/ConnectionFactory.java b/src/com/idcanet/foei/utils/jdbc/ConnectionFactory.java new file mode 100644 index 0000000..788da2f --- /dev/null +++ b/src/com/idcanet/foei/utils/jdbc/ConnectionFactory.java @@ -0,0 +1,56 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.utils.jdbc; + +import java.sql.Connection; + +/** + * Java code can get a DB connections here. + * Its retreived from the ConnectionProviderManager. + * + * @author Willem Cazander + * @version 1.0 + */ +public class ConnectionFactory +{ + /** + * Returns a connection by its name + * @param name The name of the connection + * @return Returns the Connection. + */ + static public Connection getConnection(String name) { + return getConnectionProviderManager().getConnection(name); + } + + /** + * Gets the instance of the ConnectionProviderManager. + * @return Returns the ConnectionProviderManager. + */ + static public ConnectionProviderManager getConnectionProviderManager() { + return ConnectionProviderManager.getSharedInstance(); + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/utils/jdbc/ConnectionProvider.java b/src/com/idcanet/foei/utils/jdbc/ConnectionProvider.java new file mode 100644 index 0000000..7f34bc8 --- /dev/null +++ b/src/com/idcanet/foei/utils/jdbc/ConnectionProvider.java @@ -0,0 +1,55 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.utils.jdbc; + +import java.sql.Connection; + +/** + * The ConnectionProvider is an interface which + * lets objects returns a Connection. + * + * We normally registrates an ConnectionProvider to the + * ConnectionProviderManager so objects can use it. + * + * @author Willem Cazander + * @version 1.0 Jan 4, 2006 + */ +public interface ConnectionProvider +{ + /** + * Gets the connection name for which this + * ConnectionProvider handles connections. + * @return Returns the connection name. + */ + public String getConnectionName(); + + /** + * Gets an connection of this ConnectionProvider. + * @return Returns an Connection + */ + public Connection getConnection(); +} \ No newline at end of file diff --git a/src/com/idcanet/foei/utils/jdbc/ConnectionProviderManager.java b/src/com/idcanet/foei/utils/jdbc/ConnectionProviderManager.java new file mode 100644 index 0000000..a943a4d --- /dev/null +++ b/src/com/idcanet/foei/utils/jdbc/ConnectionProviderManager.java @@ -0,0 +1,115 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.utils.jdbc; + +import java.sql.Connection; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +/** + * Manages the different ConnectionProviders. + * + * @author Willem Cazander + * @version 1.0 Jan 4, 2006 + */ +public class ConnectionProviderManager +{ + /** The logger to log to */ + private Logger logger = null; + /** The map with all connection providers */ + private Map connectionProviders = null; + /** The ConnectionProviderManager instance */ + static private ConnectionProviderManager connectionProviderManager = null; + + static { + try { + connectionProviderManager = new ConnectionProviderManager(); + } catch (Exception e) { + throw new RuntimeException("Error while creating ConnectionProviderManager",e); + } + } + + /** + * Creates an private ConnectionProviderManager + * + */ + private ConnectionProviderManager() { + logger = Logger.getLogger(ConnectionProviderManager.class.getName()); + logger.fine("Creating an ConnectionProviderManager"); + connectionProviders = new HashMap(3); + } + + /** + * Returns the singleton object of the ConnectionProviderManager. + * @return + */ + static public ConnectionProviderManager getSharedInstance() { + return connectionProviderManager; + } + + // ============ END SINGLETON + + /** + * Gets an Connection by its connectionName + * @param connectionName The connection name. + * @return Returns the Connection + */ + public Connection getConnection(String connectionName) { + return getConnectionProvider(connectionName).getConnection(); + } + + /** + * Adds an ConnectionProvider + * @param connectionProvider The ConnectionProvider to add. + */ + public void addConnectionProvider(ConnectionProvider connectionProvider) { + if(connectionProvider==null) { + throw new NullPointerException("connectionProvider may not be null."); + } + logger.fine("Adding ConnnectionProvider for connection: "+connectionProvider.getConnectionName()); + connectionProviders.put(connectionProvider.getConnectionName(),connectionProvider); + } + + /** + * Gets an ConnectionProvider by its connectionName + * @param connectionName The connection name + * @return Returns the ConnectionProvider for this connectionName. + */ + public ConnectionProvider getConnectionProvider(String connectionName) { + return connectionProviders.get(connectionName); + } + + /** + * Gets all ConnectionProviders + * @return Returns all ConnectionProviders. + */ + public Collection getConnectionProviders() { + return connectionProviders.values(); + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/utils/jdbc/JndiDataSourceProvider.java b/src/com/idcanet/foei/utils/jdbc/JndiDataSourceProvider.java new file mode 100644 index 0000000..0715a9e --- /dev/null +++ b/src/com/idcanet/foei/utils/jdbc/JndiDataSourceProvider.java @@ -0,0 +1,163 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.utils.jdbc; + +import java.sql.Connection; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.sql.DataSource; + +/** + * The JndiDataSourceProvider is an ConnectionProvider which gets its connection + * from a jndi context. + * @author Willem Cazander + * @version 1.0 Jan 4, 2006 + */ +public class JndiDataSourceProvider implements ConnectionProvider +{ + /** The context in which database datasources are found. */ + private static final String DATASOURCE_CONTEXT = "java:comp/env/jdbc/"; + /** The connectionName for this Provider */ + private String connectionName = null; + /** The jndi context to search for the dataSource. */ + private String dataSourceContext = null; + /** The logger to log to. */ + private Logger logger = null; + + /** + * Creates an JndiDataSourceProvider and inits the Logger + */ + public JndiDataSourceProvider() { + logger = Logger.getLogger(JndiDataSourceProvider.class.getName()); + } + + /** + * Creates JndiDataSourceProvider and sets its connectionName. + * @param connectionName + */ + public JndiDataSourceProvider(String connectionName) { + this(); + setConnectionName(connectionName); + } + + /** + * Creates an JndiDataSourceProvider and inits the Logger + * @param connectionName The connection name which this provider handles + * @param dataSourceContext The JNDI datasource prefix for getting the DataSource + */ + public JndiDataSourceProvider(String connectionName,String dataSourceContext) { + this(connectionName); + setDataSourceContext(dataSourceContext); + } + + /** + * Gets an DataSource out of the jndi context. + * @param name The name of the datasource in the jndi context. + * @return The datasource. + */ + static public DataSource getDataSource(String name) { + + try { + Context initialContext = new InitialContext(); + if(initialContext == null) { + throw new RuntimeException("Init: Cannot get Initial Context"); + } + DataSource datasource = (DataSource) initialContext.lookup(name); + if(datasource == null) { + throw new RuntimeException("Init: Cannot lookup datasource: '"+name+"'"); + } + return datasource; + } catch (NamingException ex) { + throw new RuntimeException("Init: Cannot get connection " + ex); + } + } + + //========= ConnectionProvider + + /** + * Gets the connection name for which this + * ConnectionProvider handles connections. + * @return Returns the connection name. + * @see ConnectionProvider#getConnectionName() + */ + public String getConnectionName() { + return connectionName; + } + + /** + * Gets an connection of this ConnectionProvider. + * @return Returns an Connection + * @see ConnectionProvider#getConnection() + */ + public Connection getConnection() { + try { + if(dataSourceContext==null) { + dataSourceContext=DATASOURCE_CONTEXT; + } + logger.finest("Trying retreiving DataSource of connectionName="+connectionName); + return getDataSource(dataSourceContext+connectionName).getConnection(); + } catch (Exception e) { + logger.log(Level.WARNING,"Error while getting DataSource",e); + throw new NullPointerException("No datasource"); + } + } + + // ==== set/getter + + /** + * Sets the connectionName. + * @param connectionName The connectionName to set. + */ + public void setConnectionName(String connectionName) { + if(connectionName==null) { + throw new NullPointerException("connectionName may not be null."); + } + logger.finest("setting connectionName="+connectionName); + this.connectionName=connectionName; + } + + /** + * @return Returns the dataSourceContext. + */ + public String getDataSourceContext() { + return dataSourceContext; + } + + /** + * When set to null(default) then + * DATASOURCE_CONTEXT is used. ("java:comp/env/jdbc/") + * @param dataSourceContext The dataSourceContext to set. + */ + public void setDataSourceContext(String dataSourceContext) { + logger.finest("setting dataSourceContext="+dataSourceContext); + this.dataSourceContext = dataSourceContext; + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/utils/jdbc/package.html b/src/com/idcanet/foei/utils/jdbc/package.html new file mode 100644 index 0000000..6992623 --- /dev/null +++ b/src/com/idcanet/foei/utils/jdbc/package.html @@ -0,0 +1,61 @@ + + + + + + +An generic ConnectionProvider with default jndi support.
+ +

Package Specification

+ +
    +
  • Full J2SE 5 compatible
  • +
  • Small package
  • +
+ + +

Related Documentation

+ +None. + + + + + \ No newline at end of file diff --git a/src/com/idcanet/foei/utils/jndi/ContextListWriter.java b/src/com/idcanet/foei/utils/jndi/ContextListWriter.java new file mode 100644 index 0000000..c771bc3 --- /dev/null +++ b/src/com/idcanet/foei/utils/jndi/ContextListWriter.java @@ -0,0 +1,70 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.utils.jndi; + +import javax.naming.Binding; +import javax.naming.Context; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import java.io.PrintStream; + +/** + * A util recursive method which prints the jndi tree. + * + * @author Willem Cazander + * @version 1.0 Jan 18, 2006 + */ +public class ContextListWriter +{ + /** + * writes an context tree to the printstream out. + * @param out The printstream to which the text line are printed. + * @param ctx The context to list. + * @param indent The intext text for sub contexts. + */ + public static void writeContextTree(PrintStream out,Context ctx, String indent) { + + if(out==null | ctx==null | indent==null) { + return; + } + try { + NamingEnumeration list = ctx.listBindings(""); + while (list.hasMore()) { + Binding item = (Binding)list.next(); + String className = item.getClassName(); + String name = item.getName(); + out.println(indent+" class: "+className+" name="+name); + Object o = item.getObject(); + if (o instanceof javax.naming.Context) { + writeContextTree(out,(Context)o,indent+indent); + } + } + } catch (NamingException ne) { + out.println("Nameing Exception: "+ne.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/utils/jndi/MemoryContext.java b/src/com/idcanet/foei/utils/jndi/MemoryContext.java new file mode 100644 index 0000000..3906a4a --- /dev/null +++ b/src/com/idcanet/foei/utils/jndi/MemoryContext.java @@ -0,0 +1,669 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.utils.jndi; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.NoSuchElementException; + +import javax.naming.Binding; +import javax.naming.CompositeName; +import javax.naming.Context; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameClassPair; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.NotContextException; +import javax.naming.OperationNotSupportedException; +import javax.naming.spi.NamingManager; + + +/** + * A sample service provider that implements a hierarchical namespace in memory. + * + * @author Willem Cazander + * @version 1.0 Jan 18, 2006 + */ +public class MemoryContext implements Context +{ + protected Hashtable myEnv; + protected Hashtable bindings = new Hashtable(11); + protected final static NameParser myParser = new MemoryContextNameParser(); + protected MemoryContext parent = null; + protected String myAtomicName = null; + + /** + * Creates an new FoeiContext without an everment + * note: + * This should be done via an Factrory + * but then the server loader can not easaly load this class + */ + public MemoryContext() + { + //super()FoeiContext(null); + } + + MemoryContext(Hashtable inEnv) + { + myEnv = (inEnv != null) + ? (Hashtable)(inEnv.clone()) + : null; + } + + protected MemoryContext(MemoryContext parent, String name, Hashtable inEnv,Hashtable bindings) + { + this(inEnv); + this.parent = parent; + myAtomicName = name; + this.bindings = (Hashtable)bindings.clone(); + } + + protected Context createFoeiContext(MemoryContext parent, String name, Hashtable inEnv) + { + return new MemoryContext(parent, name, inEnv, new Hashtable(11)); + } + + protected Context cloneCtx() + { + return new MemoryContext(parent, myAtomicName, myEnv, bindings); + } + + /** + * Utility method for processing composite/compound name. + * @param name The non-null composite or compound name to process. + * @return The non-null string name in this namespace to be processed. + */ + protected Name getMyComponents(Name name) throws NamingException + { + if (name instanceof CompositeName) + { + if (name.size() > 1) + { + throw new InvalidNameException(name.toString()+" has more components than namespace can handle"); + } + // Turn component that belongs to us into compound name + return myParser.parse(name.get(0)); + } + // Already parsed + return name; + } + + public Object lookup(String name) throws NamingException + { + return lookup(new CompositeName(name)); + } + + public Object lookup(Name name) throws NamingException + { + if (name.isEmpty()) + { + return cloneCtx(); + } + + // Extract components that belong to this namespace + Name nm = getMyComponents(name); + String atom = nm.get(0); + Object inter = bindings.get(atom); + + if (nm.size() == 1) + { + // Atomic name: Find object in internal data structure + if (inter == null) + { + throw new NameNotFoundException(name + " not found"); + } + + // Call getObjectInstance for using any object factories + try + { + return NamingManager.getObjectInstance(inter,new CompositeName().add(atom),this, myEnv); + } + catch (Exception e) + { + NamingException ne = new NamingException("getObjectInstance failed"); + ne.setRootCause(e); + throw ne; + } + } + // else + // { + // Intermediate name: Consume name in this context and continue + if (!(inter instanceof Context)) + { + throw new NotContextException(atom+" does not name a context"); + } + return ((Context)inter).lookup(nm.getSuffix(1)); + // } + } + + public void bind(String name, Object obj) throws NamingException + { + bind(new CompositeName(name), obj); + } + + public void bind(Name name, Object obj) throws NamingException + { + if (name.isEmpty()) + { + throw new InvalidNameException("Cannot bind empty name"); + } + + Name nm = getMyComponents(name); + String atom = nm.get(0); + Object inter = bindings.get(atom); + + if (nm.size() == 1) + { + // Atomic name: Find object in internal data structure + if (inter != null) + { + throw new NameAlreadyBoundException("Use rebind to override"); + } + + // Call getStateToBind for using any state factories + obj = NamingManager.getStateToBind(obj,new CompositeName().add(atom),this, myEnv); + + // Add object to internal data structure + bindings.put(atom, obj); + } + else + { + // Intermediate name: Consume name in this context and continue + if(inter==null) + { + // auto create sub context. + inter = createSubcontext(atom); + } + + if (!(inter instanceof Context)) + { + throw new NotContextException(atom+" does not name a context"); + } + ((Context)inter).bind(nm.getSuffix(1), obj); + } + } + + public void rebind(String name, Object obj) throws NamingException + { + rebind(new CompositeName(name), obj); + } + + public void rebind(Name name, Object obj) throws NamingException + { + if (name.isEmpty()) + { + throw new InvalidNameException("Cannot bind empty name"); + } + + // Extract components that belong to this namespace + Name nm = getMyComponents(name); + String atom = nm.get(0); + + if (nm.size() == 1) + { + // Atomic name + // Call getStateToBind for using any state factories + obj = NamingManager.getStateToBind(obj,new CompositeName().add(atom),this, myEnv); + + // Add object to internal data structure + bindings.put(atom, obj); + } + else + { + // Intermediate name: Consume name in this context and continue + Object inter = bindings.get(atom); + if(inter==null) + { + // auto create sub context. + inter = createSubcontext(atom); + } + + if (!(inter instanceof Context)) + { + throw new NotContextException(atom+" does not name a context"); + } + ((Context)inter).rebind(nm.getSuffix(1), obj); + } + } + + public void unbind(String name) throws NamingException + { + unbind(new CompositeName(name)); + } + + public void unbind(Name name) throws NamingException + { + if (name.isEmpty()) + { + throw new InvalidNameException("Cannot unbind empty name"); + } + + // Extract components that belong to this namespace + Name nm = getMyComponents(name); + String atom = nm.get(0); + + // Remove object from internal data structure + if (nm.size() == 1) + { + // Atomic name: Find object in internal data structure + bindings.remove(atom); + } + else + { + // Intermediate name: Consume name in this context and continue + Object inter = bindings.get(atom); + if (!(inter instanceof Context)) + { + throw new NotContextException(atom+" does not name a context"); + } + ((Context)inter).unbind(nm.getSuffix(1)); + } + } + + public void rename(String oldName, String newName) throws NamingException + { + rename(new CompositeName(oldName), new CompositeName(newName)); + } + + public void rename(Name oldname, Name newname) throws NamingException + { + if (oldname.isEmpty() || newname.isEmpty()) + { + throw new InvalidNameException("Cannot rename empty name"); + } + + Name oldnm = getMyComponents(oldname); + Name newnm = getMyComponents(newname); + + // Simplistic implementation: support only rename within same context + if (oldnm.size() != newnm.size()) + { + throw new OperationNotSupportedException("Do not support rename across different contexts"); + } + + String oldatom = oldnm.get(0); + String newatom = newnm.get(0); + + if (oldnm.size() == 1) + { + if (bindings.get(newatom) != null) + { + throw new NameAlreadyBoundException(newname.toString()+" is already bound"); + } + + // Check if old name is bound + Object oldBinding = bindings.remove(oldatom); + if (oldBinding == null) + { + throw new NameNotFoundException(oldname.toString() + " not bound"); + } + bindings.put(newatom, oldBinding); + } + else + { + if (!oldatom.equals(newatom)) + { + throw new OperationNotSupportedException("Do not support rename across different contexts"); + } + + // Intermediate name: Consume name in this context and continue + Object inter = bindings.get(oldatom); + if (!(inter instanceof Context)) + { + throw new NotContextException(oldatom+" does not name a context"); + } + ((Context)inter).rename(oldnm.getSuffix(1), newnm.getSuffix(1)); + } + } + + public NamingEnumeration list(String name) throws NamingException + { + return list(new CompositeName(name)); + } + + public NamingEnumeration list(Name name) throws NamingException + { + if (name.isEmpty()) + { + // listing this context + return new ListOfNames(bindings.keys()); + } + + // Perhaps 'name' names a context + Object target = lookup(name); + if (target instanceof Context) + { + return ((Context)target).list(""); + } + throw new NotContextException(name + " cannot be listed"); + } + + public NamingEnumeration listBindings(String name) throws NamingException + { + return listBindings(new CompositeName(name)); + } + + public NamingEnumeration listBindings(Name name) throws NamingException + { + //System.err.println("FoeiContext list bindings is called "+this+" map size:"+bindings.size()); + + if (name.isEmpty()) { + // listing this context + return new ListOfBindings(bindings.keys()); + } + + // Perhaps 'name' names a context + Object target = lookup(name); + if (target instanceof Context) { + return ((Context)target).listBindings(""); + } + throw new NotContextException(name + " cannot be listed"); + } + + public void destroySubcontext(String name) throws NamingException { + destroySubcontext(new CompositeName(name)); + } + + public void destroySubcontext(Name name) throws NamingException + { + if (name.isEmpty()) + { + throw new InvalidNameException("Cannot destroy context using empty name"); + } + + // Simplistic implementation: not checking for nonempty context first + // Use same implementation as unbind + unbind(name); + } + + public Context createSubcontext(String name) throws NamingException + { + return createSubcontext(new CompositeName(name)); + } + + public Context createSubcontext(Name name) throws NamingException + { + if (name.isEmpty()) + { + throw new InvalidNameException("Cannot bind empty name"); + } + + // Extract components that belong to this namespace + Name nm = getMyComponents(name); + String atom = nm.get(0); + Object inter = bindings.get(atom); + + if (nm.size() == 1) + { + // Atomic name: Find object in internal data structure + if (inter != null) + { + throw new NameAlreadyBoundException("Use rebind to override"); + } + + // Create child + Context child = createFoeiContext(this, atom, myEnv); + + // Add child to internal data structure + bindings.put(atom, child); + return child; + } + else + { + // Intermediate name: Consume name in this context and continue + if (!(inter instanceof Context)) + { + throw new NotContextException(atom+" does not name a context"); + } + return ((Context)inter).createSubcontext(nm.getSuffix(1)); + } + } + + public Object lookupLink(String name) throws NamingException + { + return lookupLink(new CompositeName(name)); + } + + public Object lookupLink(Name name) throws NamingException + { + return lookup(name); + } + + public NameParser getNameParser(String name) throws NamingException + { + return getNameParser(new CompositeName(name)); + } + + public NameParser getNameParser(Name name) throws NamingException + { + // Do lookup to verify name exists + Object obj = lookup(name); + if (obj instanceof Context) + { + ((Context)obj).close(); + } + return myParser; + } + + public String composeName(String name, String prefix) throws NamingException + { + Name result = composeName(new CompositeName(name),new CompositeName(prefix)); + return result.toString(); + } + + public Name composeName(Name name, Name prefix) throws NamingException + { + Name result; + + // Both are compound names, compose using compound name rules + if (!(name instanceof CompositeName) && !(prefix instanceof CompositeName)) + { + result = (Name)(prefix.clone()); + result.addAll(name); + return new CompositeName().add(result.toString()); + } + + // Simplistic implementation: do not support federation + throw new OperationNotSupportedException("Do not support composing composite names"); + } + + public Object addToEnvironment(String propName, Object propVal) throws NamingException + { + if (myEnv == null) + { + myEnv = new Hashtable(5, 0.75f); + } + return myEnv.put(propName, propVal); + } + + public Object removeFromEnvironment(String propName) throws NamingException + { + if (myEnv == null) + { + return null; + } + return myEnv.remove(propName); + } + + public Hashtable getEnvironment() throws NamingException + { + if (myEnv == null) + { + return new Hashtable(3, 0.75f); + } + else + { + return (Hashtable)myEnv.clone(); + } + } + + public String getNameInNamespace() throws NamingException + { + MemoryContext ancestor = parent; + + // No ancestor + if (ancestor == null) + { + return ""; + } + + Name name = myParser.parse(""); + name.add(myAtomicName); + + // Get parent's names + while (ancestor != null && ancestor.myAtomicName != null) + { + name.add(0, ancestor.myAtomicName); + ancestor = ancestor.parent; + } + return name.toString(); + } + + public String toString() + { + if (myAtomicName != null) + { + return myAtomicName; + } + else + { + return "ROOT CONTEXT"; + } + } + + public void close() throws NamingException + { + } + + // Class for enumerating name/class pairs + class ListOfNames implements NamingEnumeration { + protected Enumeration names; + + ListOfNames (Enumeration names) { + this.names = names; + } + + public boolean hasMoreElements() { + try { + return hasMore(); + } catch (NamingException e) { + return false; + } + } + + public boolean hasMore() throws NamingException { + return names.hasMoreElements(); + } + + public Object next() throws NamingException { + String name = (String)names.nextElement(); + String className = bindings.get(name).getClass().getName(); + return new NameClassPair(name, className); + } + + public Object nextElement() { + try { + return next(); + } catch (NamingException e) { + throw new NoSuchElementException(e.toString()); + } + } + + public void close() { + } + } + + // Class for enumerating bindings + class ListOfBindings extends ListOfNames { + + ListOfBindings(Enumeration names) { + super(names); + } + + public Object next() throws NamingException { + String name = (String)names.nextElement(); + Object obj = bindings.get(name); + + try { + obj = NamingManager.getObjectInstance(obj, + new CompositeName().add(name), MemoryContext.this, + MemoryContext.this.myEnv); + } catch (Exception e) { + NamingException ne = new NamingException( + "getObjectInstance failed"); + ne.setRootCause(e); + throw ne; + } + + return new Binding(name, obj); + } + } + + /* + static FoeiContext testRoot; + static { + try { + testRoot = new FoeiContext(null); + + Context a = testRoot.createSubcontext("a"); + Context b = a.createSubcontext("b"); + Context c = b.createSubcontext("c"); + + testRoot.createSubcontext("x"); + testRoot.createSubcontext("y"); + } catch (NamingException e) { + } + } + + public static Context getStaticNamespace(Hashtable env) { + return testRoot; + } + + public static void main(String[] args) { + try { + Context ctx = new FoeiContext(null); + + Context a = ctx.createSubcontext("a"); + Context b = a.createSubcontext("b"); + Context c = b.createSubcontext("c"); + + System.out.println(c.getNameInNamespace()); + + System.out.println(ctx.lookup("")); + System.out.println(ctx.lookup("a")); + System.out.println(ctx.lookup("b.a")); + System.out.println(a.lookup("c.b")); + } catch (NamingException e) { + e.printStackTrace(); + } + } + */ +} diff --git a/src/com/idcanet/foei/utils/jndi/MemoryContextFactory.java b/src/com/idcanet/foei/utils/jndi/MemoryContextFactory.java new file mode 100644 index 0000000..1759b50 --- /dev/null +++ b/src/com/idcanet/foei/utils/jndi/MemoryContextFactory.java @@ -0,0 +1,61 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.utils.jndi; + +import java.util.Hashtable; +import javax.naming.spi.InitialContextFactory; +import javax.naming.Context; +import javax.naming.NamingException; + + +/** + * Creates an new MemoryContext + * + * @author Willem Cazander + * @version 1.0 Jan 18, 2006 + * + */ +public class MemoryContextFactory implements InitialContextFactory +{ + /** Stores the jvm wide instance of the FoeiContext */ + static private Context context = null; + + /** + * Returns the FoeiContext + * @param environment + * @return + * @throws NamingException + */ + public Context getInitialContext(Hashtable environment) throws NamingException { + + if(context!=null) { + return context; + } + context = new MemoryContext(environment); + return context; + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/utils/jndi/MemoryContextNameParser.java b/src/com/idcanet/foei/utils/jndi/MemoryContextNameParser.java new file mode 100644 index 0000000..bf818bf --- /dev/null +++ b/src/com/idcanet/foei/utils/jndi/MemoryContextNameParser.java @@ -0,0 +1,66 @@ +/* + * Copyright 2004-2006 IDCA. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY IDCA AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IDCA OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the authors and + * should not be interpreted as representing official policies, either expressed or implied, of IDCA. + */ + +package com.idcanet.foei.utils.jndi; + +import java.util.Properties; +import javax.naming.NameParser; +import javax.naming.Name; +import javax.naming.CompoundName; +import javax.naming.NamingException; + +/** + * A jndi name parser + * + * @author Willem Cazander + * @version 1.0 Jan 18, 2006 + */ +class MemoryContextNameParser implements NameParser { + + /** The syntax to use. */ + private static Properties syntax = null; + + static { + try { + syntax = new Properties(); + syntax.put("jndi.syntax.direction", "left_to_right"); + syntax.put("jndi.syntax.separator", "."); + syntax.put("jndi.syntax.ignorecase", "false"); + syntax.put("jndi.syntax.escape", "\\"); + syntax.put("jndi.syntax.beginquote", "'"); + } catch (Exception e) { + throw new RuntimeException("Error while creating FoeiNameParser",e); + } + } + + /** + * Parses the String name into an Jndi name. + * @see NameParser#parse(java.lang.String) + */ + public Name parse(String name) throws NamingException { + return new CompoundName(name, syntax); + } +} \ No newline at end of file diff --git a/src/com/idcanet/foei/utils/jndi/package.html b/src/com/idcanet/foei/utils/jndi/package.html new file mode 100644 index 0000000..31461d4 --- /dev/null +++ b/src/com/idcanet/foei/utils/jndi/package.html @@ -0,0 +1,61 @@ + + + + + + +Defines an MemoryContext for storing object in a jndi tree.
+ +

Package Specification

+ +
    +
  • Full J2SE 5 compatible
  • +
  • Small package
  • +
+ + +

Related Documentation

+ +None. + + + + + \ No newline at end of file diff --git a/tests/com/META-INF/foei-config.xml b/tests/com/META-INF/foei-config.xml new file mode 100644 index 0000000..05f5afd --- /dev/null +++ b/tests/com/META-INF/foei-config.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tests/com/META-INF/foei.properties b/tests/com/META-INF/foei.properties new file mode 100644 index 0000000..4bcc195 --- /dev/null +++ b/tests/com/META-INF/foei.properties @@ -0,0 +1,26 @@ + +foei.context_name=TEST-0 + +foei.event_thread_listeners=tests.TestEventThreadListener + +foei.event_executor_manager.pool_core_size=5 +foei.event_executor_manager.pool_max_size=10 +foei.event_executor_manager.pool_keep_alive=300 + +############ +## DEFAULTS ## +############ +# +#foei.context_name= +#foei.root_path= +# +#foei.object_bindings_manager=com.idca.foei.core.impl.ObjectBindingsManagerImpl +#foei.event_executor=com.idca.foei.core.impl.EventExecutorImpl +#foei.event_executor_manager=com.idca.foei.core.impl.EventExecutorManagerImpl +#foei.event_executor_manager.pool_core_size=3 +#foei.event_executor_manager.pool_max_size=5 +#foei.event_executor_manager.pool_keep_alive=180 +#foei.initial_object_context_factory=com.idca.foei.utils.jndi.MemoryContextFactory +#foei.event_thread_listeners= +#foei.x2o_root_tag=foei +#foei.x2o_default_element_configurator=com.idca.foei.xml.x2o.DefaultX2OElementConfigurator diff --git a/tests/com/idcanet/foei/tests/SimpleFoeiTests.java b/tests/com/idcanet/foei/tests/SimpleFoeiTests.java index 6eb88fd..6df99cc 100644 --- a/tests/com/idcanet/foei/tests/SimpleFoeiTests.java +++ b/tests/com/idcanet/foei/tests/SimpleFoeiTests.java @@ -1,3 +1,14 @@ -dfg \ No newline at end of file +package com.idcanet.foei.tests; + + + +/** + * + * + * @author Willem Cazander + * @version 1.0 Jul 27, 2006 + */ +public class SimpleFoeiTests { +} \ No newline at end of file diff --git a/tests/com/idcanet/foei/tests/TestEventThreadListener.java b/tests/com/idcanet/foei/tests/TestEventThreadListener.java new file mode 100644 index 0000000..3bcf79b --- /dev/null +++ b/tests/com/idcanet/foei/tests/TestEventThreadListener.java @@ -0,0 +1,22 @@ + +package com.idcanet.foei.tests; + +import com.idcanet.foei.core.EventThreadListener; +import com.idcanet.foei.core.FoeiContext; + +/** + * + * + * @author Willem Cazander + * @version 1.0 Jul 27, 2006 + */ +public class TestEventThreadListener implements EventThreadListener { + + public void startThread(FoeiContext foeiContext) { + System.out.println("START: "+Thread.currentThread().getName()+" context: "+foeiContext.getName()); + } + + public void stopThread(FoeiContext foeiContext) { + System.out.println("STOP: "+Thread.currentThread().getName()+" context: "+foeiContext.getName()); + } +} \ No newline at end of file