exo-jcr SVN: r3260 - jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing.
by do-not-reply@jboss.org
Author: tolusha
Date: 2010-10-08 06:07:12 -0400 (Fri, 08 Oct 2010)
New Revision: 3260
Modified:
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/SystemViewImporter.java
Log:
EXOJCR-955: NPE when try to import data via WorkspaceContentImporter
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/SystemViewImporter.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/SystemViewImporter.java 2010-10-08 09:34:35 UTC (rev 3259)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/SystemViewImporter.java 2010-10-08 10:07:12 UTC (rev 3260)
@@ -314,7 +314,7 @@
checkProperties(currentNodePropertiesInfo);
}
- mapNodePropertiesInfo.remove(currentNodeInfo.getQPath().getAsString());
+ mapNodePropertiesInfo.remove(currentNodeInfo.getIdentifier());
currentNodeInfo.setMixinTypeNames(currentNodeInfo.getMixinTypeNames());
15 years, 9 months
exo-jcr SVN: r3259 - in jcr/branches/1.12.x/exo.jcr.component.core: src/main/java/org/exoplatform/services/jcr/impl/xml/importing and 1 other directory.
by do-not-reply@jboss.org
Author: tolusha
Date: 2010-10-08 05:34:35 -0400 (Fri, 08 Oct 2010)
New Revision: 3259
Modified:
jcr/branches/1.12.x/exo.jcr.component.core/pom.xml
jcr/branches/1.12.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/SystemViewImporter.java
jcr/branches/1.12.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/WorkspaceContentImporter.java
Log:
EXOJCR-955: NPE when try to import data via WorkspaceContentImporter
Modified: jcr/branches/1.12.x/exo.jcr.component.core/pom.xml
===================================================================
--- jcr/branches/1.12.x/exo.jcr.component.core/pom.xml 2010-10-08 09:07:54 UTC (rev 3258)
+++ jcr/branches/1.12.x/exo.jcr.component.core/pom.xml 2010-10-08 09:34:35 UTC (rev 3259)
@@ -409,7 +409,6 @@
<exclude>org/exoplatform/services/jcr/**/impl/**/TestRepositoryManagement.java</exclude>
<exclude>org/exoplatform/services/jcr/**/impl/**/TestSaveConfiguration.java</exclude>
<exclude>org/exoplatform/services/jcr/**/impl/**/ValueStoragePluginTest.java</exclude>
- <exclude>org/exoplatform/services/jcr/**/impl/**/TestWorkspaceRestore.java</exclude>
<exclude>org/exoplatform/services/jcr/**/impl/**/TestSessionCleaner.java</exclude>
<exclude>org/exoplatform/services/jcr/**/impl/**/Base*.java</exclude>
<exclude>org/exoplatform/services/jcr/**/impl/**/TestJCRSerializationStream.java</exclude>
Modified: jcr/branches/1.12.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/SystemViewImporter.java
===================================================================
--- jcr/branches/1.12.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/SystemViewImporter.java 2010-10-08 09:07:54 UTC (rev 3258)
+++ jcr/branches/1.12.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/SystemViewImporter.java 2010-10-08 09:34:35 UTC (rev 3259)
@@ -18,21 +18,6 @@
*/
package org.exoplatform.services.jcr.impl.xml.importing;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.NamespaceRegistry;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.ValueFormatException;
-import javax.jcr.nodetype.ConstraintViolationException;
-import javax.jcr.nodetype.NoSuchNodeTypeException;
-
import org.exoplatform.services.jcr.access.AccessManager;
import org.exoplatform.services.jcr.core.ExtendedPropertyType;
import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
@@ -62,6 +47,21 @@
import org.exoplatform.services.log.Log;
import org.exoplatform.services.security.ConversationState;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.ValueFormatException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+
/**
* Created by The eXo Platform SAS.
*
@@ -159,7 +159,7 @@
ImportNodeData currentNodeInfo = (ImportNodeData)getParent();
- NodePropertiesInfo currentNodePropertiesInfo = mapNodePropertiesInfo.get(currentNodeInfo.getQPath().getAsString());
+ NodePropertiesInfo currentNodePropertiesInfo = mapNodePropertiesInfo.get(currentNodeInfo.getIdentifier());
currentNodePropertiesInfo.addProperty(propertyData);
}
@@ -219,7 +219,7 @@
changesLog.add(new ItemState(newNodeData, ItemState.ADDED, true, getAncestorToSave()));
- mapNodePropertiesInfo.put(newNodeData.getQPath().getAsString(), new NodePropertiesInfo(newNodeData));
+ mapNodePropertiesInfo.put(newNodeData.getIdentifier(), new NodePropertiesInfo(newNodeData));
tree.push(newNodeData);
@@ -307,14 +307,14 @@
{
ImportNodeData currentNodeInfo = (ImportNodeData)tree.pop();
- NodePropertiesInfo currentNodePropertiesInfo = mapNodePropertiesInfo.get(currentNodeInfo.getQPath().getAsString());
+ NodePropertiesInfo currentNodePropertiesInfo = mapNodePropertiesInfo.get(currentNodeInfo.getIdentifier());
if (currentNodePropertiesInfo != null)
{
checkProperties(currentNodePropertiesInfo);
}
- mapNodePropertiesInfo.remove(currentNodeInfo.getQPath().getAsString());
+ mapNodePropertiesInfo.remove(currentNodeInfo.getIdentifier());
currentNodeInfo.setMixinTypeNames(currentNodeInfo.getMixinTypeNames());
@@ -567,8 +567,8 @@
tree.push(currentNodeInfo);
- mapNodePropertiesInfo.put(currentNodeInfo.getQPath().getAsString(), new NodePropertiesInfo(currentNodeInfo));
-
+ mapNodePropertiesInfo.put(currentNodeInfo.getIdentifier(), new NodePropertiesInfo(currentNodeInfo));
+
return propertyData;
}
Modified: jcr/branches/1.12.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/WorkspaceContentImporter.java
===================================================================
--- jcr/branches/1.12.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/WorkspaceContentImporter.java 2010-10-08 09:07:54 UTC (rev 3258)
+++ jcr/branches/1.12.x/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/WorkspaceContentImporter.java 2010-10-08 09:34:35 UTC (rev 3259)
@@ -18,6 +18,11 @@
*/
package org.exoplatform.services.jcr.impl.xml.importing;
+import java.util.Map;
+
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.RepositoryException;
+
import org.exoplatform.services.jcr.access.AccessControlList;
import org.exoplatform.services.jcr.access.AccessManager;
import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
@@ -35,11 +40,6 @@
import org.exoplatform.services.log.Log;
import org.exoplatform.services.security.ConversationState;
-import java.util.Map;
-
-import javax.jcr.NamespaceRegistry;
-import javax.jcr.RepositoryException;
-
/**
* Created by The eXo Platform SAS.
*
@@ -136,6 +136,8 @@
changesLog.add(new ItemState(newNodeData, ItemState.ADDED, true, parentData.getQPath()));
}
tree.push(newNodeData);
+
+ mapNodePropertiesInfo.put(newNodeData.getIdentifier(), new NodePropertiesInfo(newNodeData));
}
else
{
15 years, 9 months
exo-jcr SVN: r3258 - in jcr/trunk/exo.jcr.component.core: src/main/java/org/exoplatform/services/jcr/impl/xml/importing and 1 other directory.
by do-not-reply@jboss.org
Author: tolusha
Date: 2010-10-08 05:07:54 -0400 (Fri, 08 Oct 2010)
New Revision: 3258
Modified:
jcr/trunk/exo.jcr.component.core/pom.xml
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/SystemViewImporter.java
jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/WorkspaceContentImporter.java
Log:
EXOJCR-955: NPE when try to import data via WorkspaceContentImporter
Modified: jcr/trunk/exo.jcr.component.core/pom.xml
===================================================================
--- jcr/trunk/exo.jcr.component.core/pom.xml 2010-10-07 07:26:21 UTC (rev 3257)
+++ jcr/trunk/exo.jcr.component.core/pom.xml 2010-10-08 09:07:54 UTC (rev 3258)
@@ -420,7 +420,6 @@
<exclude>org/exoplatform/services/jcr/**/impl/**/TestDBCleanerService.java</exclude>
<exclude>org/exoplatform/services/jcr/**/impl/**/TestSaveConfiguration.java</exclude>
<exclude>org/exoplatform/services/jcr/**/impl/**/ValueStoragePluginTest.java</exclude>
- <exclude>org/exoplatform/services/jcr/**/impl/**/TestWorkspaceRestore.java</exclude>
<exclude>org/exoplatform/services/jcr/**/impl/**/TestSessionCleaner.java</exclude>
<exclude>org/exoplatform/services/jcr/**/impl/**/Base*.java</exclude>
<exclude>org/exoplatform/services/jcr/**/impl/**/TestJCRSerializationStream.java</exclude>
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/SystemViewImporter.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/SystemViewImporter.java 2010-10-07 07:26:21 UTC (rev 3257)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/SystemViewImporter.java 2010-10-08 09:07:54 UTC (rev 3258)
@@ -18,6 +18,21 @@
*/
package org.exoplatform.services.jcr.impl.xml.importing;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.ValueFormatException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+
import org.exoplatform.services.jcr.access.AccessManager;
import org.exoplatform.services.jcr.core.ExtendedPropertyType;
import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
@@ -47,21 +62,6 @@
import org.exoplatform.services.log.Log;
import org.exoplatform.services.security.ConversationState;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.jcr.NamespaceRegistry;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.ValueFormatException;
-import javax.jcr.nodetype.ConstraintViolationException;
-import javax.jcr.nodetype.NoSuchNodeTypeException;
-
/**
* Created by The eXo Platform SAS.
*
@@ -159,7 +159,7 @@
ImportNodeData currentNodeInfo = (ImportNodeData)getParent();
- NodePropertiesInfo currentNodePropertiesInfo = mapNodePropertiesInfo.get(currentNodeInfo.getQPath().getAsString());
+ NodePropertiesInfo currentNodePropertiesInfo = mapNodePropertiesInfo.get(currentNodeInfo.getIdentifier());
currentNodePropertiesInfo.addProperty(propertyData);
}
@@ -219,7 +219,7 @@
changesLog.add(new ItemState(newNodeData, ItemState.ADDED, true, getAncestorToSave()));
- mapNodePropertiesInfo.put(newNodeData.getQPath().getAsString(), new NodePropertiesInfo(newNodeData));
+ mapNodePropertiesInfo.put(newNodeData.getIdentifier(), new NodePropertiesInfo(newNodeData));
tree.push(newNodeData);
@@ -307,7 +307,7 @@
{
ImportNodeData currentNodeInfo = (ImportNodeData)tree.pop();
- NodePropertiesInfo currentNodePropertiesInfo = mapNodePropertiesInfo.get(currentNodeInfo.getQPath().getAsString());
+ NodePropertiesInfo currentNodePropertiesInfo = mapNodePropertiesInfo.get(currentNodeInfo.getIdentifier());
if (currentNodePropertiesInfo != null)
{
@@ -571,7 +571,7 @@
tree.push(currentNodeInfo);
- mapNodePropertiesInfo.put(currentNodeInfo.getQPath().getAsString(), new NodePropertiesInfo(currentNodeInfo));
+ mapNodePropertiesInfo.put(currentNodeInfo.getIdentifier(), new NodePropertiesInfo(currentNodeInfo));
return propertyData;
}
Modified: jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/WorkspaceContentImporter.java
===================================================================
--- jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/WorkspaceContentImporter.java 2010-10-07 07:26:21 UTC (rev 3257)
+++ jcr/trunk/exo.jcr.component.core/src/main/java/org/exoplatform/services/jcr/impl/xml/importing/WorkspaceContentImporter.java 2010-10-08 09:07:54 UTC (rev 3258)
@@ -18,6 +18,11 @@
*/
package org.exoplatform.services.jcr.impl.xml.importing;
+import java.util.Map;
+
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.RepositoryException;
+
import org.exoplatform.services.jcr.access.AccessControlList;
import org.exoplatform.services.jcr.access.AccessManager;
import org.exoplatform.services.jcr.core.nodetype.NodeTypeDataManager;
@@ -35,11 +40,6 @@
import org.exoplatform.services.log.Log;
import org.exoplatform.services.security.ConversationState;
-import java.util.Map;
-
-import javax.jcr.NamespaceRegistry;
-import javax.jcr.RepositoryException;
-
/**
* Created by The eXo Platform SAS.
*
@@ -136,6 +136,8 @@
changesLog.add(new ItemState(newNodeData, ItemState.ADDED, true, parentData.getQPath()));
}
tree.push(newNodeData);
+
+ mapNodePropertiesInfo.put(newNodeData.getIdentifier(), new NodePropertiesInfo(newNodeData));
}
else
{
15 years, 9 months
exo-jcr SVN: r3257 - jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel.
by do-not-reply@jboss.org
Author: tolusha
Date: 2010-10-07 03:26:21 -0400 (Thu, 07 Oct 2010)
New Revision: 3257
Modified:
jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/initialcontext-binder-service.xml
jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/jndi-naming.xml
Log:
EXOJCR-977: support different files for different InitialContextBinder instances
Modified: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/initialcontext-binder-service.xml
===================================================================
--- jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/initialcontext-binder-service.xml 2010-10-07 07:25:24 UTC (rev 3256)
+++ jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/initialcontext-binder-service.xml 2010-10-07 07:26:21 UTC (rev 3257)
@@ -1,59 +1,47 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
-"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="Kernel.InitialContextBinderservice">
- <?dbhtml filename="ch-initialcontext-binder-service.html"?>
- <title>Initial Context Binder service</title>
-
- <para>Initial Context Binder is responsible for binding references at
- runtime, persisting in file and automatically rebinding after restart. Java
- temp directory is used to persist references in bind-references.xml
- file.</para>
-
- <note>
- <para>Available since Kernel 2.2.1-GA</para>
- </note>
-
- <section>
- <title>API</title>
-
- <para>Service provide methods for binding reference.</para>
-
- <programlisting>public void bind(String bindName, String className, String factory, String factoryLocation, Map<String, String> refAddr) throws NamingException, FileNotFoundException, XMLStreamExcept</programlisting>
-
- <itemizedlist>
- <listitem>
- <para>bindName - name of binding</para>
- </listitem>
-
- <listitem>
- <para>className - the fully-qualified name of the class of the object
- to which this Reference refers</para>
- </listitem>
-
- <listitem>
- <para>factory - the name of the factory class for creating an instance
- of the object to which this Reference refers</para>
- </listitem>
-
- <listitem>
- <para>factoryLocation - the location of the factory class</para>
- </listitem>
-
- <listitem>
- <para>refAddr - object's properties map</para>
- </listitem>
- </itemizedlist>
- </section>
-
- <section>
- <title>Configuration</title>
-
- <para>A configuration example</para>
-
- <programlisting><component>
- <key>org.exoplatform.services.naming.InitialContextBinder</key>
- <type>org.exoplatform.services.naming.InitialContextBinder</type>
-</component></programlisting>
- </section>
-</chapter>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<chapter id="Kernel.InitialContextBinderservice">
+ <?dbhtml filename="ch-initialcontext-binder-service.html"?>
+
+ <title>Initial Context Binder</title>
+
+ <para>Initial Context Binder is responsible for binding references at
+ runtime, persisting in file and automatically rebinding. Java temp directory
+ is used to persist references in bind-references.xml file by default. In
+ case when need to definde special file it can be done by add parameter to
+ <link linkend="Kernel.JNDINaming">InitialContextInitializer</link>
+ configuration.</para>
+
+ <section>
+ <title>API</title>
+
+ <para>Service provide methods for binding reference.</para>
+
+ <programlisting>public void bind(String bindName, String className, String factory, String factoryLocation, Map<String, String> refAddr) throws NamingException, FileNotFoundException, XMLStreamExcept</programlisting>
+
+ <itemizedlist>
+ <listitem>
+ <para>bindName - name of binding</para>
+ </listitem>
+
+ <listitem>
+ <para>className - the fully-qualified name of the class of the object
+ to which this Reference refers</para>
+ </listitem>
+
+ <listitem>
+ <para>factory - the name of the factory class for creating an instance
+ of the object to which this Reference refers</para>
+ </listitem>
+
+ <listitem>
+ <para>factoryLocation - the location of the factory class</para>
+ </listitem>
+
+ <listitem>
+ <para>refAddr - object's properties map</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+</chapter>
Modified: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/jndi-naming.xml
===================================================================
--- jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/jndi-naming.xml 2010-10-07 07:25:24 UTC (rev 3256)
+++ jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/jndi-naming.xml 2010-10-07 07:26:21 UTC (rev 3257)
@@ -131,9 +131,18 @@
<description>Mandatory initial context properties</description>
<property name="java.naming.provider.url" value="rmi://localhost:9999"/>
</properties-param>
+ <value-param>.
+ <name>bindings-store-path</name>.
+ <value>bind-references.xml</value>.
+ </value-param>.
</init-params>
</component></programlisting></para>
+ <para>where</para>
+
+ <para><emphasis role="bold">binding-store-path</emphasis> is file path
+ which stores binded datasources in runtime</para>
+
<para>The <envar>BindReferencePlugin</envar> component plugin
configuration example (for JDBC datasource):</para>
@@ -188,9 +197,7 @@
<para><envar>InitialContextInitalizer</envar> also provides feature of
references binding in runtime. References have bind in runtime will be
- persisted and automatically rebinded on a next system start. Java temp
- directory is used to persist references in bind-references.xml
- file.</para>
+ persisted and automatically rebinded on a next system start.</para>
<para>Service provides methods for binding reference.</para>
15 years, 9 months
exo-jcr SVN: r3256 - in kernel/trunk/exo.kernel.component.common: src/main/java/org/exoplatform/services/naming and 2 other directories.
by do-not-reply@jboss.org
Author: tolusha
Date: 2010-10-07 03:25:24 -0400 (Thu, 07 Oct 2010)
New Revision: 3256
Modified:
kernel/trunk/exo.kernel.component.common/pom.xml
kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/naming/InitialContextBinder.java
kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/naming/InitialContextInitializer.java
kernel/trunk/exo.kernel.component.common/src/test/java/org/exoplatform/services/naming/InitialContextTest.java
kernel/trunk/exo.kernel.component.common/src/test/resources/conf/portal/test-configuration.xml
Log:
EXOJCR-977: support different files for different InitialContextBinder instances
Modified: kernel/trunk/exo.kernel.component.common/pom.xml
===================================================================
--- kernel/trunk/exo.kernel.component.common/pom.xml 2010-10-07 06:54:54 UTC (rev 3255)
+++ kernel/trunk/exo.kernel.component.common/pom.xml 2010-10-07 07:25:24 UTC (rev 3256)
@@ -105,7 +105,6 @@
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
- <exclude>**/InitialContextTest.java</exclude>
<exclude>**/TransactionTest.java</exclude>
</excludes>
</configuration>
Modified: kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/naming/InitialContextBinder.java
===================================================================
--- kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/naming/InitialContextBinder.java 2010-10-07 06:54:54 UTC (rev 3255)
+++ kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/naming/InitialContextBinder.java 2010-10-07 07:25:24 UTC (rev 3256)
@@ -25,8 +25,8 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Stack;
-import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import javax.naming.NameAlreadyBoundException;
@@ -91,20 +91,16 @@
* initial context initializer
* @param initParams
* initialization parameters
- * @throws XMLStreamException
* @throws FileNotFoundException
- * @throws FileNotFoundException
* @throws XMLStreamException
- * @throws NamingException
* @throws NamingException
*/
- InitialContextBinder(InitialContextInitializer initialContextInitializer) throws FileNotFoundException,
- XMLStreamException, NamingException
+ InitialContextBinder(InitialContextInitializer initialContextInitializer, String bindingsStorePath)
+ throws FileNotFoundException, XMLStreamException, NamingException
{
this.initialContextInitializer = initialContextInitializer;
-
this.bindings = new ConcurrentHashMap<String, Reference>();
- this.bindingsStorePath = System.getProperty("java.io.tmpdir") + File.separator + "bind-references.xml";
+ this.bindingsStorePath = bindingsStorePath;
if (new File(bindingsStorePath).exists())
{
@@ -117,6 +113,15 @@
}
/**
+ * InitialContextBinder constructor.
+ */
+ InitialContextBinder(InitialContextInitializer initialContextInitializer) throws FileNotFoundException,
+ XMLStreamException, NamingException
+ {
+ this(initialContextInitializer, InitialContextInitializer.DEFAULT_BINDING_STORE_PATH);
+ }
+
+ /**
* Constructs references from params, binds in initial contexts and persists list of all binded
* references into file.
*
Modified: kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/naming/InitialContextInitializer.java
===================================================================
--- kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/naming/InitialContextInitializer.java 2010-10-07 06:54:54 UTC (rev 3255)
+++ kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/naming/InitialContextInitializer.java 2010-10-07 07:25:24 UTC (rev 3256)
@@ -23,9 +23,11 @@
import org.exoplatform.container.xml.InitParams;
import org.exoplatform.container.xml.PropertiesParam;
import org.exoplatform.container.xml.Property;
+import org.exoplatform.container.xml.ValueParam;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
+import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collection;
@@ -55,6 +57,11 @@
final public static String PROPERTIES_MANDATORY = "mandatory-properties";
+ final public static String BINDINGS_STORE_PATH = "bindings-store-path";
+
+ final public static String DEFAULT_BINDING_STORE_PATH = System.getProperty("java.io.tmpdir") + File.separator
+ + "bind-references.xml";
+
private static Log LOG = ExoLogger.getLogger("exo.kernel.component.common.InitialContextInitializer");
private List<BindReferencePlugin> bindReferencesPlugins;
@@ -107,8 +114,18 @@
initialContext = new InitialContext();
bindReferencesPlugins = new ArrayList<BindReferencePlugin>();
+ ValueParam bindingStorePathParam = params.getValueParam(BINDINGS_STORE_PATH);
+
// binder
- binder = new InitialContextBinder(this);
+ if (bindingStorePathParam == null)
+ {
+ binder = new InitialContextBinder(this, DEFAULT_BINDING_STORE_PATH);
+ }
+ else
+ {
+ binder = new InitialContextBinder(this, bindingStorePathParam.getValue());
+ }
+
}
private void setSystemProperty(String propName, String propValue, String propParamName)
@@ -133,7 +150,7 @@
initialContext.rebind(name, reference);
// binder
- binder = new InitialContextBinder(this);
+ binder = new InitialContextBinder(this, DEFAULT_BINDING_STORE_PATH);
}
/**
Modified: kernel/trunk/exo.kernel.component.common/src/test/java/org/exoplatform/services/naming/InitialContextTest.java
===================================================================
--- kernel/trunk/exo.kernel.component.common/src/test/java/org/exoplatform/services/naming/InitialContextTest.java 2010-10-07 06:54:54 UTC (rev 3255)
+++ kernel/trunk/exo.kernel.component.common/src/test/java/org/exoplatform/services/naming/InitialContextTest.java 2010-10-07 07:25:24 UTC (rev 3256)
@@ -18,18 +18,24 @@
*/
package org.exoplatform.services.naming;
-import junit.framework.TestCase;
-
-import org.exoplatform.container.StandaloneContainer;
-
+import java.io.File;
+import java.io.FileNotFoundException;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import javax.naming.CompositeName;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.xml.stream.XMLStreamException;
+import junit.framework.TestCase;
+
+import org.exoplatform.container.PortalContainer;
+
/**
* Created by The eXo Platform SAS .<br/> Prerequisites: default-context-factory
* = org.exoplatform.services.naming.impl.SimpleContextFactory
@@ -42,14 +48,14 @@
private static String TEST_CONTEXT_FACTORY = "org.exoplatform.services.naming.SimpleContextFactory";
- private StandaloneContainer container;
+ private PortalContainer container;
public void setUp() throws Exception
{
- StandaloneContainer.setConfigurationPath("src/test/java/conf/standalone/test-configuration.xml");
+ // StandaloneContainer.setConfigurationPath("src/test/resources/conf/standalone/test-configuration.xml");
- container = StandaloneContainer.getInstance();
+ container = PortalContainer.getInstance();
}
public void testConfig() throws Exception
@@ -98,4 +104,27 @@
}
}
+ /*
+ * Tests if InitialContextInitializer correctly gets bindings-store-path from
+ * param-value and pass it to InitialContexBinder, thus provides usage of different files
+ * for different instances of the class.
+ */
+ public void testDifferentFileUsage() throws FileNotFoundException, NamingException, XMLStreamException
+ {
+
+ InitialContextInitializer initializer =
+ (InitialContextInitializer)container.getComponentInstanceOfType(InitialContextInitializer.class);
+
+ Map<String, String> refAddr = new HashMap<String, String>();
+ refAddr.put("driverClassName", "org.hsqldb.jdbcDriver");
+ refAddr.put("url", "jdbc:hsqldb:file:target/temp/data/portal");
+ refAddr.put("username", "sa");
+ refAddr.put("password", "");
+
+ initializer.bind("testjdbcjcr1", "javax.sql.DataSource", "org.apache.commons.dbcp.BasicDataSourceFactory", null,
+ refAddr);
+
+ assertTrue(new File("target/store-path.xml").exists());
+ }
+
}
Modified: kernel/trunk/exo.kernel.component.common/src/test/resources/conf/portal/test-configuration.xml
===================================================================
--- kernel/trunk/exo.kernel.component.common/src/test/resources/conf/portal/test-configuration.xml 2010-10-07 06:54:54 UTC (rev 3255)
+++ kernel/trunk/exo.kernel.component.common/src/test/resources/conf/portal/test-configuration.xml 2010-10-07 07:25:24 UTC (rev 3256)
@@ -52,11 +52,6 @@
</component>
<component>
- <key>org.exoplatform.services.naming.InitialContextBinder</key>
- <type>org.exoplatform.services.naming.InitialContextBinder</type>
- </component>
-
- <component>
<key>org.exoplatform.services.mail.MailService</key>
<type>org.exoplatform.services.mail.impl.MailServiceImpl</type>
<init-params>
@@ -78,6 +73,84 @@
</component>
<component>
+ <key>org.exoplatform.services.naming.InitialContextInitializer</key>
+ <type>org.exoplatform.services.naming.InitialContextInitializer</type>
+ <component-plugins>
+ <component-plugin>
+ <name>bind.datasource</name>
+ <set-method>addPlugin</set-method>
+ <type>org.exoplatform.services.naming.BindReferencePlugin</type>
+ <init-params>
+ <value-param>
+ <name>bind-name</name>
+ <value>jdbcjcr</value>
+ </value-param>
+ <value-param>
+ <name>class-name</name>
+ <value>javax.sql.DataSource</value>
+ </value-param>
+ <value-param>
+ <name>factory</name>
+ <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
+ </value-param>
+ <properties-param>
+ <name>ref-addresses</name>
+ <description>ref-addresses</description>
+ <property name="driverClassName" value="org.hsqldb.jdbcDriver" />
+ <property name="url" value="jdbc:hsqldb:file:target/temp/data/portal" />
+ <property name="username" value="sa" />
+ <property name="password" value="" />
+ </properties-param>
+ </init-params>
+ </component-plugin>
+
+ <component-plugin>
+ <name>tx.userTransaction</name>
+ <set-method>addPlugin</set-method>
+ <type>org.exoplatform.services.naming.BindReferencePlugin</type>
+ <init-params>
+ <value-param>
+ <name>bind-name</name>
+ <value>UserTransaction</value>
+ </value-param>
+ <value-param>
+ <name>class-name</name>
+ <value>javax.transaction.UserTransaction</value>
+ </value-param>
+ <value-param>
+ <name>factory</name>
+ <value>org.objectweb.jotm.UserTransactionFactory</value>
+ <!-- value>org.exoplatform.services.transaction.UserTransactionFactory</value -->
+ </value-param>
+ <properties-param>
+ <name>ref-addresses</name>
+ <description>ref-addresses</description>
+ <property name="timeout" value="60" />
+ </properties-param>
+ </init-params>
+ </component-plugin>
+ </component-plugins>
+ <init-params>
+ <value-param>
+ <name>bindings-store-path</name>
+ <value>target/store-path.xml</value>
+ </value-param>
+ <properties-param>
+ <name>default-properties</name>
+ <description>Default initial context properties</description>
+ <property name="java.naming.factory.initial" value="org.exoplatform.services.naming.SimpleContextFactory" />
+ </properties-param>
+ <!-- properties-param>
+ <name>mandatory-properties</name>
+ <description>Mandatory initial context properties</description>
+ <property name="java.naming.factory.initial" value="org.exoplatform.services.naming.SimpleContextFactory" />
+ <property name="java.naming.provider.url" value="rmi://localhost:9999" />
+ </properties-param -->
+ </init-params>
+ </component>
+
+
+ <component>
<key>org.exoplatform.services.scheduler.JobSchedulerService</key>
<type>org.exoplatform.services.scheduler.impl.JobSchedulerServiceImpl</type>
<component-plugins>
15 years, 9 months
exo-jcr SVN: r3255 - ws/trunk/exo.ws.rest.core/src/main/java/org/exoplatform/services/rest/impl/provider.
by do-not-reply@jboss.org
Author: aparfonov
Date: 2010-10-07 02:54:54 -0400 (Thu, 07 Oct 2010)
New Revision: 3255
Modified:
ws/trunk/exo.ws.rest.core/src/main/java/org/exoplatform/services/rest/impl/provider/JsonEntityProvider.java
Log:
EXOJCR-992 : exclude some more types
Modified: ws/trunk/exo.ws.rest.core/src/main/java/org/exoplatform/services/rest/impl/provider/JsonEntityProvider.java
===================================================================
--- ws/trunk/exo.ws.rest.core/src/main/java/org/exoplatform/services/rest/impl/provider/JsonEntityProvider.java 2010-10-06 17:09:15 UTC (rev 3254)
+++ ws/trunk/exo.ws.rest.core/src/main/java/org/exoplatform/services/rest/impl/provider/JsonEntityProvider.java 2010-10-07 06:54:54 UTC (rev 3255)
@@ -34,6 +34,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
+import java.io.Writer;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Collection;
@@ -68,10 +69,11 @@
// Or probably enough check only content type 'application/json'
// and if this content type set trust it and try parse/write
- /** Do not process via JSON "known" JAX-RS types. */
+ /** Do not process via JSON "known" JAX-RS types and some more. */
private static final Class<?>[] IGNORED =
- new Class<?>[]{byte[].class, DataSource.class, DOMSource.class, File.class, InputStream.class, JAXBElement.class,
- MultivaluedMap.class, Reader.class, SAXSource.class, StreamingOutput.class, StreamSource.class, String.class};
+ new Class<?>[]{byte[].class, char[].class, DataSource.class, DOMSource.class, File.class, InputStream.class,
+ OutputStream.class, JAXBElement.class, MultivaluedMap.class, Reader.class, Writer.class, SAXSource.class,
+ StreamingOutput.class, StreamSource.class, String.class};
private static boolean isIgnored(Class<?> type)
{
15 years, 9 months
exo-jcr SVN: r3254 - in jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules: kernel and 1 other directory.
by do-not-reply@jboss.org
Author: nfilotto
Date: 2010-10-06 13:09:15 -0400 (Wed, 06 Oct 2010)
New Revision: 3254
Added:
jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/rpc-service.xml
Modified:
jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel.xml
Log:
EXOJCR-967: The doc
Added: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/rpc-service.xml
===================================================================
--- jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/rpc-service.xml (rev 0)
+++ jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel/rpc-service.xml 2010-10-06 17:09:15 UTC (rev 3254)
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<chapter id="Kernel.RPCService">
+ <?dbhtml filename="ch-rpc-service.html"?>
+
+ <title>RPC Service</title>
+
+ <section>
+ <title>Description</title>
+
+ <para>The <emphasis>RPCService</emphasis> is only needed in a cluser
+ environment, it is used to communicate with the other cluster nodes. It
+ allows to execute a command on all the cluster nodes or on the coordinator
+ i.e. the oldest node in the cluster. The <emphasis>RPCService</emphasis>
+ has been designed to rely on JGroups capabilites and should not be used
+ for heavy load. It can be used for example to notify other nodes that
+ something happened or to collect some information from the other
+ nodes.</para>
+
+ <para>The <emphasis>RPCService</emphasis> relies on 2 main interfaces
+ which are the <emphasis>org.exoplatform.services.rpc.RPCService</emphasis>
+ that defines the service itslef and the
+ <emphasis>org.exoplatform.services.rpc.RemoteCommand</emphasis> that
+ defines the command that we can execute on other nodes. The arguments that
+ will be given to the <emphasis>RemoteCommand</emphasis> must be
+ <emphasis>Serializable</emphasis> and its return type also in order to
+ prevent any issue due to the serialization. To prevent to execute any
+ <emphasis>RemoteCommand</emphasis> that could be malicious and to allow to
+ use non <emphasis>Serializable</emphasis> command, you need to register
+ the command first before using it. Since the service will keep only one
+ instance of <emphasis>RemoteCommand</emphasis> per command Id, the
+ implementation of the <emphasis>RemoteCommand</emphasis> must be thread
+ safe.</para>
+
+ <para>To be usable, all the <emphasis>RemoteCommand</emphasis>s must be
+ registered before being used on all the cluster nodes, which means that
+ the command registration must be done in the constructor of your component
+ in other words before that the <emphasis>RPCService</emphasis> is started.
+ If you try to launch a command that has been registered but the
+ <emphasis>RPCService</emphasis> is not yet launched, you will get an
+ <emphasis>RPCException</emphasis> due to an illegal state. This has for
+ consequences that you will be able to execute a command only once your
+ component will be started.</para>
+
+ <para>See an example below:</para>
+
+ <programlisting>public class MyService implements Startable
+{
+ private RPCService rpcService;
+ private RemoteCommand sayHelloCommand;
+
+ public MyService(RPCService rpcService)
+ {
+ this.rpcService = rpcService;
+ // Register the command before that the RPCService is started
+ sayHelloCommand = rpcService.registerCommand(new RemoteCommand()
+ {
+ public Serializable execute(Serializable[] args) throws Throwable
+ {
+ System.out.println("Hello !");
+ return null;
+ }
+
+ public String getId()
+ {
+ return "hello-world-command";
+ }
+ });
+ }
+
+ public void start()
+ {
+ // Since the RPCService is a dependency of RPCService, it will be started before
+ // so I can execute my command
+ try
+ {
+ // This will make all the nodes say "Hello !"
+ rpcService.executeCommandOnAllNodes(sayHelloCommand, false);
+ }
+ catch (SecurityException e)
+ {
+ e.printStackTrace();
+ }
+ catch (RPCException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public void stop()
+ {
+ }
+}</programlisting>
+
+ <para>In the previous example, We register the command
+ <emphasis>sayHelloCommand</emphasis> in the constructor of
+ <emphasis>MyService</emphasis> and we execute this command in the start
+ method.</para>
+
+ <note>
+ <para>We expect to have one <emphasis>RPCService</emphasis> instance per
+ <emphasis>PortalContainer</emphasis> in a portal mode and only one
+ <emphasis>RPCService</emphasis> instance in a standalone mode</para>
+ </note>
+ </section>
+
+ <section>
+ <title>Configuration</title>
+
+ <para>The configuration of the <emphasis>RPCService</emphasis> should be
+ added only in a cluster environment. See below an example of
+ configuration</para>
+
+ <programlisting><configuration>
+....
+ <component>
+ <key>org.exoplatform.services.rpc.RPCService</key>
+ <type>org.exoplatform.services.rpc.impl.RPCServiceImpl</type>
+ <init-params>
+ <value-param>
+ <name>jgroups-configuration</name>
+ <value>classpath:/udp.xml</value>
+ </value-param>
+ <value-param>
+ <name>jgroups-cluster-name</name>
+ <value>RPCService-Cluster</value>
+ </value-param>
+ <value-param>
+ <name>jgroups-default-timeout</name>
+ <value>0</value>
+ </value-param>
+ </init-params>
+ </component>
+...
+</configuration></programlisting>
+
+ <table>
+ <title>Fields description</title>
+
+ <tgroup cols="2">
+ <tbody>
+ <row>
+ <entry><emphasis>jgroups-configuration</emphasis></entry>
+
+ <entry>This is the location of the configuration of jgroups. This
+ parameter is mandatory.</entry>
+ </row>
+
+ <row>
+ <entry><emphasis>jgroups-cluster-name</emphasis></entry>
+
+ <entry>This is the name of the cluster. This parameter is optional
+ and its default value is <emphasis>RPCService-Cluster</emphasis>.
+ Since we could have several instances of the
+ <emphasis>RPCService</emphasis>, the final name will be
+ "${jgroups-cluster-name}-${container-name}"</entry>
+ </row>
+
+ <row>
+ <entry><emphasis>jgroups-default-timeout</emphasis></entry>
+
+ <entry>This is the default timeout to use if the timeout is not
+ given, if no response could be get after this timeout an exception
+ will be thrown. This parameter is optional and its default value
+ is 0 which means that we don't use any timeout by default.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
+
+ <section>
+ <title>The SingleMethodCallCommand</title>
+
+ <para>Most of the time we only need to call a method on a given object,
+ this can be done thanks to the
+ <emphasis>org.exoplatform.services.rpc.SingleMethodCallCommand</emphasis>
+ which is the implementation of a <emphasis>RemoteCommand</emphasis>
+ proposed by default. This command will dynamically execute a method on a
+ given object.</para>
+
+ <programlisting>// Register the command first
+RemoteCommand commandGetName = rpcService.registerCommand(new SingleMethodCallCommand(myService, "getName"));
+// Execute the command on the coordinator
+String name = rpcService.executeCommandOnCoordinator(commandGetName, true);
+// Print the name
+System.out.println("Name : " + name);</programlisting>
+
+ <para>This example:</para>
+
+ <orderedlist>
+ <listitem>
+ <para>Register a <emphasis>SingleMethodCallCommand</emphasis> that
+ will call <emphasis>getName()</emphasis> on the Object
+ <emphasis>myService</emphasis> anytime the command will be
+ executed.</para>
+ </listitem>
+
+ <listitem>
+ <para>Execute the command synchronously on the coordinator, assuming
+ that the same command (with the same id) has already been registered
+ on the coordinator</para>
+ </listitem>
+
+ <listitem>
+ <para>Print the name got from the coordinator</para>
+ </listitem>
+ </orderedlist>
+ </section>
+</chapter>
Modified: jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel.xml
===================================================================
--- jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel.xml 2010-10-06 15:35:09 UTC (rev 3253)
+++ jcr/trunk/exo.jcr.docs/exo.jcr.docs.developer/en/src/main/docbook/en-US/modules/kernel.xml 2010-10-06 17:09:15 UTC (rev 3254)
@@ -56,5 +56,8 @@
<xi:include href="kernel/listener-service.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="kernel/rpc-service.xml"
+ xmlns:xi="http://www.w3.org/2001/XInclude" />
</part>
15 years, 9 months
exo-jcr SVN: r3253 - kernel/trunk/exo.kernel.component.common/src/test/java/org/exoplatform/services/rpc/impl.
by do-not-reply@jboss.org
Author: nfilotto
Date: 2010-10-06 11:35:09 -0400 (Wed, 06 Oct 2010)
New Revision: 3253
Modified:
kernel/trunk/exo.kernel.component.common/src/test/java/org/exoplatform/services/rpc/impl/TestRPCServiceImpl.java
Log:
EXOJCR-967: Extends the timeout to prevent issue with TestRPCServiceImpl.testSeveralNodes
Modified: kernel/trunk/exo.kernel.component.common/src/test/java/org/exoplatform/services/rpc/impl/TestRPCServiceImpl.java
===================================================================
--- kernel/trunk/exo.kernel.component.common/src/test/java/org/exoplatform/services/rpc/impl/TestRPCServiceImpl.java 2010-10-06 14:10:44 UTC (rev 3252)
+++ kernel/trunk/exo.kernel.component.common/src/test/java/org/exoplatform/services/rpc/impl/TestRPCServiceImpl.java 2010-10-06 15:35:09 UTC (rev 3253)
@@ -581,7 +581,7 @@
public String execute(Serializable[] args) throws Throwable
{
- Thread.sleep(20000);
+ Thread.sleep(30000);
return "OldCoordinator";
}
});
15 years, 9 months
exo-jcr SVN: r3252 - in kernel/trunk/exo.kernel.component.common: src/main/java/org/exoplatform/services and 6 other directories.
by do-not-reply@jboss.org
Author: nfilotto
Date: 2010-10-06 10:10:44 -0400 (Wed, 06 Oct 2010)
New Revision: 3252
Added:
kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/
kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/RPCException.java
kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/RPCService.java
kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/RemoteCommand.java
kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/SingleMethodCallCommand.java
kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/impl/
kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/impl/RPCServiceImpl.java
kernel/trunk/exo.kernel.component.common/src/test/java/org/exoplatform/services/rpc/
kernel/trunk/exo.kernel.component.common/src/test/java/org/exoplatform/services/rpc/impl/
kernel/trunk/exo.kernel.component.common/src/test/java/org/exoplatform/services/rpc/impl/TestRPCServiceImpl.java
kernel/trunk/exo.kernel.component.common/src/test/resources/conf/portal/udp.xml
Modified:
kernel/trunk/exo.kernel.component.common/pom.xml
Log:
EXOJCR-967: Implementation of the RPCService
Modified: kernel/trunk/exo.kernel.component.common/pom.xml
===================================================================
--- kernel/trunk/exo.kernel.component.common/pom.xml 2010-10-06 09:31:29 UTC (rev 3251)
+++ kernel/trunk/exo.kernel.component.common/pom.xml 2010-10-06 14:10:44 UTC (rev 3252)
@@ -93,6 +93,10 @@
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
</dependency>
+ <dependency>
+ <groupId>jgroups</groupId>
+ <artifactId>jgroups</artifactId>
+ </dependency>
</dependencies>
<build>
<plugins>
Added: kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/RPCException.java
===================================================================
--- kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/RPCException.java (rev 0)
+++ kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/RPCException.java 2010-10-06 14:10:44 UTC (rev 3252)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.rpc;
+
+/**
+ * The root class of all the Exception related to the RPC Service
+ *
+ * @author <a href="mailto:nicolas.filotto@exoplatform.com">Nicolas Filotto</a>
+ * @version $Id$
+ */
+public class RPCException extends Exception
+{
+
+ /**
+ * The serial version UID
+ */
+ private static final long serialVersionUID = -9113831373947878170L;
+
+ public RPCException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+ public RPCException(String message)
+ {
+ super(message);
+ }
+}
Added: kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/RPCService.java
===================================================================
--- kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/RPCService.java (rev 0)
+++ kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/RPCService.java 2010-10-06 14:10:44 UTC (rev 3252)
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.rpc;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * This service provides mechanism to communicate with the other cluster nodes. This service will
+ * be based of JGroups as an underlying Transport.
+ * @author <a href="mailto:nicolas.filotto@exoplatform.com">Nicolas Filotto</a>
+ * @version $Id$
+ */
+public interface RPCService
+{
+
+ /**
+ * The permission needed to access to any methods of the RPCService
+ */
+ public static final RuntimePermission ACCESS_RPC_SERVICE_PERMISSION = new RuntimePermission("accessRPCService");
+
+ /**
+ * Executes a command on all the cluster nodes. This method is equivalent to the other method of the
+ * same type but with the default timeout. The command must be registered first otherwise an
+ * {@link RPCException} will be thrown.
+ *
+ * @param command The command to execute on each cluster node
+ * @param synchronous if true, sets group request mode to {@link org.jgroups.blocks.GroupRequest#GET_ALL},
+ * and if false sets it to {@link org.jgroups.blocks.GroupRequest#GET_NONE}.
+ * @param args an array of {@link Serializable} objects corresponding to parameters of the command
+ * to execute remotely
+ * @return a list of responses from all the members of the cluster. If we met an exception on a given node,
+ * the RPCException will be the corresponding response of this particular node
+ * @throws RPCException in the event of problems.
+ * @throws SecurityException if the {@link SecurityManager} is installed and the call method
+ * doesn't have the {@link RuntimePermission} <code>ACCESS_RPC_SERVICE_PERMISSION</code>
+ */
+ List<Object> executeCommandOnAllNodes(RemoteCommand command, boolean synchronous, Serializable... args)
+ throws RPCException, SecurityException;
+
+ /**
+ * Executes a command synchronously on all the cluster nodes. The command must be registered first otherwise an
+ * {@link RPCException} will be thrown.
+ *
+ * @param command The command to execute on each cluster node
+ * @param timeout a timeout after which to throw a replication exception.
+ * @param args an array of {@link Serializable} objects corresponding to parameters of the command
+ * to execute remotely
+ * @return a list of responses from all the members of the cluster. If we met an exception on a given node,
+ * the RPCException will be the corresponding response of this particular node
+ * @throws RPCException in the event of problems.
+ * @throws SecurityException if the {@link SecurityManager} is installed and the call method
+ * doesn't have the {@link RuntimePermission} <code>ACCESS_RPC_SERVICE_PERMISSION</code>
+ */
+ List<Object> executeCommandOnAllNodes(RemoteCommand command, long timeout, Serializable... args)
+ throws RPCException, SecurityException;
+
+ /**
+ * Executes a command on the coordinator only. This method is equivalent to the other method of the
+ * same type but with the default timeout. The command must be registered first otherwise an
+ * {@link RPCException} will be thrown.
+ *
+ * @param command The command to execute on the coordinator node
+ * @param synchronous if true, sets group request mode to {@link org.jgroups.blocks.GroupRequest#GET_ALL},
+ * and if false sets it to {@link org.jgroups.blocks.GroupRequest#GET_NONE}.
+ * @param args an array of {@link Serializable} objects corresponding to parameters of the command
+ * to execute remotely
+ * @return the response of the coordinator.
+ * @throws RPCException in the event of problems.
+ * @throws SecurityException if the {@link SecurityManager} is installed and the call method
+ * doesn't have the {@link RuntimePermission} <code>ACCESS_RPC_SERVICE_PERMISSION</code>
+ */
+ Object executeCommandOnCoordinator(RemoteCommand command, boolean synchronous, Serializable... args)
+ throws RPCException, SecurityException;
+
+ /**
+ * Executes a command synchronously on the coordinator only. The command must be registered first otherwise an
+ * {@link RPCException} will be thrown.
+ *
+ * @param command The command to execute on the coordinator node
+ * @param timeout a timeout after which to throw a replication exception.
+ * @param args an array of {@link Serializable} objects corresponding to parameters of the command
+ * to execute remotely
+ * @return the response of the coordinator.
+ * @throws RPCException in the event of problems.
+ * @throws SecurityException if the {@link SecurityManager} is installed and the call method
+ * doesn't have the {@link RuntimePermission} <code>ACCESS_RPC_SERVICE_PERMISSION</code>
+ */
+ Object executeCommandOnCoordinator(RemoteCommand command, long timeout, Serializable... args) throws RPCException,
+ SecurityException;
+
+ /**
+ * Register a new {@link RemoteCommand} instance, it will be mapped to its id. If a command with the
+ * same Id has already been registered, a warning will be printed into the log file and the new
+ * command will replace the old one.
+ * @param command the instance of the {@link RemoteCommand} to register
+ * @return the command itself if it could be registered null otherwise
+ * @throws SecurityException if the {@link SecurityManager} is installed and the call method
+ * doesn't have the {@link RuntimePermission} <code>ACCESS_RPC_SERVICE_PERMISSION</code>
+ */
+ RemoteCommand registerCommand(RemoteCommand command) throws SecurityException;
+
+ /**
+ * Unregister a {@link RemoteCommand} instance, if the id is known or the instance itself is known
+ * otherwise it will be ignored
+ * @param command the command to unregister
+ * @throws SecurityException if the {@link SecurityManager} is installed and the call method
+ * doesn't have the {@link RuntimePermission} <code>ACCESS_RPC_SERVICE_PERMISSION</code>
+ */
+ void unregisterCommand(RemoteCommand command) throws SecurityException;
+}
\ No newline at end of file
Added: kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/RemoteCommand.java
===================================================================
--- kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/RemoteCommand.java (rev 0)
+++ kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/RemoteCommand.java 2010-10-06 14:10:44 UTC (rev 3252)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.rpc;
+
+import java.io.Serializable;
+
+/**
+ * This class represents the command that can be executed on a remote server.
+ * A RemoteCommand needs to be ThreadSafe since it can be re-used by several
+ * threads in parallel.
+ * @author <a href="mailto:nicolas.filotto@exoplatform.com">Nicolas Filotto</a>
+ * @version $Id$
+ */
+public interface RemoteCommand
+{
+ /**
+ * This method will execute the command on the local machine.
+ * @param container The container from which the services needed for the command
+ * will be extracted
+ * @param args The parameters needed to execute the command
+ * @return arbitrary return value generated by performing this command
+ * @throws Throwable in the event of problems.
+ */
+ Serializable execute(Serializable[] args) throws Throwable;
+
+ /**
+ * Gives the id of the command
+ * @return the unique ID of the command
+ */
+ String getId();
+}
Added: kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/SingleMethodCallCommand.java
===================================================================
--- kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/SingleMethodCallCommand.java (rev 0)
+++ kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/SingleMethodCallCommand.java 2010-10-06 14:10:44 UTC (rev 3252)
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.rpc;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+
+/**
+ * This command will allow you to call one specific method with the arguments given by the execute method
+ * on a component.
+ *
+ * @author <a href="mailto:nicolas.filotto@exoplatform.com">Nicolas Filotto</a>
+ * @version $Id$
+ */
+public class SingleMethodCallCommand implements RemoteCommand
+{
+
+ /**
+ * The component on which we want to execute the method
+ */
+ private final Object component;
+
+ /**
+ * The method that we want to call
+ */
+ private final Method method;
+
+ /**
+ * The id of the command
+ */
+ private final String id;
+
+ /**
+ *
+ * @param component the component on which we want to execute the method
+ * @param methodName the name of the method
+ * @param parameterTypes the parameter array
+ * @throws NoSuchMethodException if a matching method is not found.
+ * @exception SecurityException
+ * If a security manager, <i>s</i>, is present and any of the
+ * following conditions is met:
+ *
+ * <ul>
+ *
+ * <li> invocation of
+ * <tt>{@link SecurityManager#checkMemberAccess
+ * s.checkMemberAccess(this, Member.DECLARED)}</tt> denies
+ * access to the declared method
+ *
+ * <li> the caller's class loader is not the same as or an
+ * ancestor of the class loader for the current class and
+ * invocation of <tt>{@link SecurityManager#checkPackageAccess
+ * s.checkPackageAccess()}</tt> denies access to the package
+ * of this class
+ *
+ * </ul>
+ * @throws ClassNotFoundException If the last parameter type is an array and we
+ * cannot find the type of the array
+ */
+ public SingleMethodCallCommand(Object component, String methodName, Class<?>... parameterTypes)
+ throws SecurityException, NoSuchMethodException, ClassNotFoundException
+ {
+ if (component == null)
+ {
+ throw new IllegalArgumentException("The component cannot be null");
+ }
+ if (methodName == null || (methodName = methodName.trim()).length() == 0)
+ {
+ throw new IllegalArgumentException("The methodName cannot be empty");
+ }
+ this.component = component;
+ this.method = component.getClass().getDeclaredMethod(methodName, parameterTypes);
+ if (!Modifier.isPublic(method.getModifiers()))
+ {
+ throw new IllegalArgumentException("The method '" + methodName + "' is not public");
+ }
+ this.id = getId(component, method);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Serializable execute(Serializable[] args) throws Throwable
+ {
+ try
+ {
+ return (Serializable)method.invoke(component, (Object[])args);
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Could not execute the method " + id + " with the arguments " + Arrays.toString(args), e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getId()
+ {
+ return id;
+ }
+
+ /**
+ * Gives a unique Id from the component and the method
+ */
+ private static String getId(Object component, Method method)
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append(component.getClass().getName());
+ sb.append('.');
+ sb.append(method.getName());
+ sb.append('(');
+ boolean first = true;
+ for (Class<?> c : method.getParameterTypes())
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ sb.append(',');
+ }
+ sb.append(c.getSimpleName());
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+}
Added: kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/impl/RPCServiceImpl.java
===================================================================
--- kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/impl/RPCServiceImpl.java (rev 0)
+++ kernel/trunk/exo.kernel.component.common/src/main/java/org/exoplatform/services/rpc/impl/RPCServiceImpl.java 2010-10-06 14:10:44 UTC (rev 3252)
@@ -0,0 +1,788 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.rpc.impl;
+
+import org.exoplatform.commons.utils.PropertyManager;
+import org.exoplatform.container.ExoContainer;
+import org.exoplatform.container.ExoContainerContext;
+import org.exoplatform.container.configuration.ConfigurationManager;
+import org.exoplatform.container.xml.InitParams;
+import org.exoplatform.container.xml.ValueParam;
+import org.exoplatform.services.log.ExoLogger;
+import org.exoplatform.services.log.Log;
+import org.exoplatform.services.rpc.RPCException;
+import org.exoplatform.services.rpc.RPCService;
+import org.exoplatform.services.rpc.RemoteCommand;
+import org.jgroups.Address;
+import org.jgroups.Channel;
+import org.jgroups.ChannelException;
+import org.jgroups.JChannel;
+import org.jgroups.MembershipListener;
+import org.jgroups.Message;
+import org.jgroups.View;
+import org.jgroups.blocks.GroupRequest;
+import org.jgroups.blocks.MessageDispatcher;
+import org.jgroups.blocks.RequestHandler;
+import org.jgroups.conf.ConfiguratorFactory;
+import org.jgroups.conf.ProtocolStackConfigurator;
+import org.jgroups.util.Rsp;
+import org.jgroups.util.RspList;
+import org.picocontainer.Startable;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * This class is a basic implementation of the {@link RPCService}, it is mainly based on the
+ * {@link MessageDispatcher}. This implementation is not designed to give the best possible
+ * performances, it only aims to give a way to communicate with other nodes.
+ *
+ * @author <a href="mailto:nicolas.filotto@exoplatform.com">Nicolas Filotto</a>
+ * @version $Id$
+ */
+public class RPCServiceImpl implements RPCService, Startable, RequestHandler, MembershipListener
+{
+
+ /**
+ * Connection logger.
+ */
+ private static final Log LOG = ExoLogger.getLogger("exo.kernel.component.common.RPCServiceImpl");
+
+ /**
+ * The name of the parameter for the location of the JGroups configuration.
+ */
+ public static final String PARAM_JGROUPS_CONFIG = "jgroups-configuration";
+
+ /**
+ * The name of the parameter for the name of the cluster.
+ */
+ public static final String PARAM_CLUSTER_NAME = "jgroups-cluster-name";
+
+ /**
+ * The name of the parameter for the default timeout
+ */
+ public static final String PARAM_DEFAULT_TIMEOUT = "jgroups-default-timeout";
+
+ /**
+ * The value of the default timeout
+ */
+ public static final int DEFAULT_TIMEOUT = 0;
+
+ /**
+ * The default value of the cluster name
+ */
+ public static final String CLUSTER_NAME = "RPCService-Cluster";
+
+ /**
+ * The configurator used to create the JGroups Channel
+ */
+ private final ProtocolStackConfigurator configurator;
+
+ /**
+ * The name of the cluster
+ */
+ private final String clusterName;
+
+ /**
+ * The JGroups Channel used to communicate with other nodes
+ */
+ protected Channel channel;
+
+ /**
+ * The current list of all the members of the cluster
+ */
+ protected volatile Vector<Address> members;
+
+ /**
+ * The address of the current coordinator
+ */
+ protected volatile Address coordinator;
+
+ /**
+ * The default value of the timeout
+ */
+ private long defaultTimeout = DEFAULT_TIMEOUT;
+
+ /**
+ * The dispatcher used to launch the command of the cluster nodes
+ */
+ private MessageDispatcher dispatcher;
+
+ /**
+ * The signal that indicates that the service is started, it will be used
+ * to make the application wait until the service is fully started to
+ * ensure that all the commands have been registered before handling
+ * incoming messages.
+ */
+ private final CountDownLatch startSignal = new CountDownLatch(1);
+
+ /**
+ * Current State of the {@link RPCServiceImpl}
+ */
+ private volatile State state;
+
+ /**
+ * All the commands that have been registered
+ */
+ private volatile Map<String, RemoteCommand> commands =
+ Collections.unmodifiableMap(new HashMap<String, RemoteCommand>());
+
+ /**
+ * The public constructor
+ * @param ctx the {@link ExoContainerContext} from which we will extract the corresponding
+ * {@link ExoContainer}
+ * @param params the list of initial parameters
+ * @param configManager the configuration manager used to get the configuration
+ * of JGroups
+ */
+ public RPCServiceImpl(ExoContainerContext ctx, InitParams params, ConfigurationManager configManager)
+ {
+ if (params == null)
+ {
+ throw new IllegalArgumentException("The RPCServiceImpl requires some parameters");
+ }
+ URL properties = getProperties(params, configManager);
+ if (LOG.isInfoEnabled())
+ {
+ LOG.info("The JGroups configuration used for the RPCServiceImpl will be loaded from " + properties);
+ }
+ try
+ {
+ this.configurator = ConfiguratorFactory.getStackConfigurator(properties);
+ }
+ catch (ChannelException e)
+ {
+ throw new RuntimeException("Cannot load the JGroups configuration from " + properties, e);
+ }
+ this.clusterName = getClusterName(ctx, params);
+ if (LOG.isDebugEnabled())
+ {
+ LOG.debug("The cluster name of the RPCServiceImpl has been set to " + clusterName);
+ }
+ String sTimeout = getValueParam(params, PARAM_DEFAULT_TIMEOUT);
+ if (sTimeout != null)
+ {
+ defaultTimeout = Integer.parseInt(sTimeout);
+ if (LOG.isDebugEnabled())
+ {
+ LOG.debug("The default timeout of the RPCServiceImpl has been set to " + defaultTimeout);
+ }
+ }
+ this.state = State.INITIALIZED;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<Object> executeCommandOnAllNodes(RemoteCommand command, boolean synchronous, Serializable... args)
+ throws RPCException
+ {
+ return executeCommandOnAllNodesMain(command, synchronous, defaultTimeout, args);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public List<Object> executeCommandOnAllNodes(RemoteCommand command, long timeout, Serializable... args)
+ throws RPCException
+ {
+ return executeCommandOnAllNodesMain(command, true, timeout, args);
+ }
+
+ /**
+ * Executes a command on all the cluster nodes. This method is equivalent to the other method of the
+ * same type but with the default timeout. The command must be registered first otherwise an
+ * {@link RPCException} will be thrown.
+ *
+ * @param command The command to execute on each cluster node
+ * @param synchronous if true, sets group request mode to {@link org.jgroups.blocks.GroupRequest#GET_ALL},
+ * and if false sets it to {@link org.jgroups.blocks.GroupRequest#GET_NONE}.
+ * @param timeout a timeout after which to throw a replication exception.
+ * @param args an array of {@link Serializable} objects corresponding to parameters of the command
+ * to execute remotely
+ * @return a list of responses from all the members of the cluster. If we met an exception on a given node,
+ * the RPCException will be the corresponding response of this particular node
+ * @throws RPCException in the event of problems.
+ */
+ protected List<Object> executeCommandOnAllNodesMain(RemoteCommand command, boolean synchronous, long timeout,
+ Serializable... args) throws RPCException
+ {
+ return excecuteCommand(members, command, synchronous, timeout, args);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object executeCommandOnCoordinator(RemoteCommand command, boolean synchronous, Serializable... args)
+ throws RPCException
+ {
+ return executeCommandOnCoordinatorMain(command, synchronous, defaultTimeout, args);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object executeCommandOnCoordinator(RemoteCommand command, long timeout, Serializable... args)
+ throws RPCException
+ {
+ return executeCommandOnCoordinatorMain(command, true, timeout, args);
+ }
+
+ /**
+ * Executes a command on the coordinator only. This method is equivalent to the other method of the
+ * same type but with the default timeout. The command must be registered first otherwise an
+ * {@link RPCException} will be thrown.
+ *
+ * @param command The command to execute on the coordinator node
+ * @param synchronous if true, sets group request mode to {@link org.jgroups.blocks.GroupRequest#GET_ALL},
+ * and if false sets it to {@link org.jgroups.blocks.GroupRequest#GET_NONE}.
+ * @param timeout a timeout after which to throw a replication exception.
+ * @param args an array of {@link Serializable} objects corresponding to parameters of the command
+ * to execute remotely
+ * @return the response of the coordinator.
+ * @throws RPCException in the event of problems.
+ */
+ protected Object executeCommandOnCoordinatorMain(RemoteCommand command, boolean synchronous, long timeout,
+ Serializable... args) throws RPCException
+ {
+ Address coordinator = this.coordinator;
+ Vector<Address> v = new Vector<Address>(1);
+ v.add(coordinator);
+ List<Object> lResults = excecuteCommand(v, command, synchronous, timeout, args);
+ Object result = lResults == null || lResults.size() == 0 ? null : lResults.get(0);
+ if (result instanceof MemberHasLeftException)
+ {
+ if (coordinator.equals(this.coordinator))
+ {
+ throw new RPCException("The coordinator did not change, we faced an unexpected situation",
+ (MemberHasLeftException)result);
+ }
+ else
+ {
+ // The coordinator has changed, we will automatically retry with the new coordinator
+ return executeCommandOnCoordinator(command, synchronous, timeout, args);
+ }
+ }
+ else if (result instanceof RPCException)
+ {
+ throw (RPCException)result;
+ }
+ return result;
+ }
+
+ /**
+ * Execute the command on all the nodes corresponding to the list of destinations.
+ * @param dests the list of members on which the command needs to be executed
+ * @param command the command to execute
+ * @param synchronous if true, sets group request mode to {@link org.jgroups.blocks.GroupRequest#GET_ALL}, and if false sets
+ * it to {@link org.jgroups.blocks.GroupRequest#GET_NONE}.
+ * @param timeout a timeout after which to throw a replication exception.
+ * @param args the list of parameters
+ * @return a list of responses from all the targeted members of the cluster.
+ * @throws RPCException in the event of problems.
+ */
+ protected List<Object> excecuteCommand(final Vector<Address> dests, RemoteCommand command,
+ final boolean synchronous, final long timeout, Serializable... args) throws RPCException
+ {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null)
+ {
+ security.checkPermission(RPCService.ACCESS_RPC_SERVICE_PERMISSION);
+ }
+ if (state != State.STARTED)
+ {
+ throw new RPCException(
+ "Cannot execute any commands if the service is not started, the current state of the service is " + state);
+ }
+ String commandId = command.getId();
+ if (commands.get(commandId) != command)
+ {
+ throw new RPCException("Command " + commandId + " unknown, please register your command first");
+ }
+ final Message msg = new Message();
+ msg.setObject(new MessageBody(commandId, args));
+ RspList rsps = AccessController.doPrivileged(new PrivilegedAction<RspList>()
+ {
+ public RspList run()
+ {
+ return dispatcher.castMessage(dests, msg, synchronous ? GroupRequest.GET_ALL : GroupRequest.GET_NONE,
+ timeout);
+ }
+ });
+
+ if (LOG.isTraceEnabled())
+ LOG.trace("responses: " + rsps);
+ if (rsps == null)
+ throw new RPCException("Could not get the responses for command " + commandId + ".");
+ if (!synchronous)
+ return Collections.emptyList();// async case
+ if (LOG.isTraceEnabled())
+ {
+ LOG.trace("(" + channel.getLocalAddress() + "): responses for command " + commandId + ":\n" + rsps);
+ }
+ List<Object> retval = new ArrayList<Object>(rsps.size());
+ for (Address dest : dests)
+ {
+ Rsp rsp = rsps.get(dest);
+ if (rsp == null || (rsp.wasSuspected() && !rsp.wasReceived()))
+ {
+ // The corresponding member has left
+ retval.add(new MemberHasLeftException("No response for the member " + dest
+ + ", this member has probably left the cluster."));
+ }
+ else if (!rsp.wasReceived())
+ {
+ retval.add(new RPCException("Replication timeout for " + rsp.getSender() + ", rsp=" + rsp));
+ }
+ else
+ {
+ Object value = rsp.getValue();
+ if (value instanceof RPCException)
+ {
+ // if we have any application-level exceptions make sure we throw them!!
+ if (LOG.isTraceEnabled())
+ LOG.trace("Recieved exception'" + value + "' from " + rsp.getSender(), (RPCException)value);
+ }
+ retval.add(value);
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object handle(Message msg)
+ {
+ String commandId = null;
+ try
+ {
+ // Ensure that the service is fully started before trying to execute any command
+ startSignal.await();
+ MessageBody body = (MessageBody)msg.getObject();
+ RemoteCommand command = getCommand(commandId = body.getCommandId());
+ if (command == null)
+ {
+ return new RPCException("Command " + commandId + " unkown, please register your command first");
+ }
+ Object execResult = command.execute(body.getArgs());
+ if (LOG.isTraceEnabled())
+ LOG.trace("Command : " + commandId + " executed, result is: " + execResult);
+ return execResult;
+ }
+ catch (Throwable x)
+ {
+ if (LOG.isTraceEnabled())
+ LOG.trace("Problems invoking command.", x);
+ return new RPCException("Cannot execute the command " + (commandId == null ? "" : commandId), x);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void block()
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void suspect(Address suspectedMbr)
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void viewAccepted(View view)
+ {
+ this.members = view.getMembers();
+ this.coordinator = members != null && members.size() > 0 ? members.get(0) : null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized RemoteCommand registerCommand(RemoteCommand command)
+ {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null)
+ {
+ security.checkPermission(RPCService.ACCESS_RPC_SERVICE_PERMISSION);
+ }
+ if (command != null)
+ {
+ String commandId = command.getId();
+ if (commandId == null)
+ {
+ throw new IllegalArgumentException("The command Id cannot be null");
+ }
+ Map<String, RemoteCommand> tmpCommands = new HashMap<String, RemoteCommand>(this.commands);
+ RemoteCommand oldCommand = tmpCommands.put(commandId, command);
+ if (oldCommand != null && PropertyManager.isDevelopping())
+ {
+ LOG.warn("A command has already been registered with the id " + commandId
+ + ", this command will be replaced with the new one");
+ }
+ this.commands = Collections.unmodifiableMap(tmpCommands);
+ return command;
+ }
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized void unregisterCommand(RemoteCommand command)
+ {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null)
+ {
+ security.checkPermission(RPCService.ACCESS_RPC_SERVICE_PERMISSION);
+ }
+ if (command != null)
+ {
+ String commandId = command.getId();
+ if (commandId == null)
+ {
+ throw new IllegalArgumentException("The command Id cannot be null");
+ }
+ if (commands.get(commandId) != command)
+ {
+ // We prevent to remove any command that has not been registered, thus we expect that
+ // the registered instance is exactly the same instance as the one that we want to
+ // unregister
+ if (PropertyManager.isDevelopping())
+ {
+ LOG.warn("Cannot unregister an unknown RemoteCommand, either the command id " + commandId
+ + " is unknown or the instance of RemoteCommand to unregister is unknown");
+ }
+ return;
+ }
+ Map<String, RemoteCommand> tmpCommands = new HashMap<String, RemoteCommand>(this.commands);
+ tmpCommands.remove(commandId);
+ this.commands = Collections.unmodifiableMap(tmpCommands);
+ }
+ }
+
+ /**
+ * Gives the {@link RemoteCommand} corresponding to the given id
+ * @param commandId the command id of the command to retrieve
+ * @return the corresponding {@link RemoteCommand}
+ */
+ protected RemoteCommand getCommand(String commandId)
+ {
+ return commands.get(commandId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void start()
+ {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null)
+ {
+ security.checkPermission(RPCService.ACCESS_RPC_SERVICE_PERMISSION);
+ }
+ try
+ {
+ this.channel = new JChannel(configurator);
+ channel.setOpt(Channel.AUTO_RECONNECT, true);
+ this.dispatcher = new MessageDispatcher(channel, null, this, this);
+ doPriviledgedExceptionAction(new PrivilegedExceptionAction<Void>()
+ {
+ public Void run() throws Exception
+ {
+ channel.connect(clusterName);
+ return null;
+ }
+ });
+ }
+ catch (ChannelException e)
+ {
+ throw new RuntimeException("Cannot initialize the Channel needed for the RPCServiceImpl", e);
+ }
+ finally
+ {
+ this.state = State.STARTED;
+ startSignal.countDown();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stop()
+ {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null)
+ {
+ security.checkPermission(RPCService.ACCESS_RPC_SERVICE_PERMISSION);
+ }
+ this.state = State.STOPPED;
+ if (channel != null && channel.isOpen())
+ {
+ if (LOG.isInfoEnabled())
+ LOG.info("Disconnecting and closing the Channel");
+ AccessController.doPrivileged(new PrivilegedAction<Void>()
+ {
+ public Void run()
+ {
+ channel.disconnect();
+ return null;
+ }
+ });
+ channel.close();
+ channel = null;
+ }
+ if (dispatcher != null)
+ {
+ dispatcher.stop();
+ dispatcher = null;
+ }
+ }
+
+ /**
+ * Gives the value of the default timeout
+ * @return the default timeout
+ */
+ public long getDefaultTimeout()
+ {
+ return defaultTimeout;
+ }
+
+ /**
+ * Gives the name of the cluster
+ * @return the name of the cluster
+ */
+ public String getClusterName()
+ {
+ return clusterName;
+ }
+
+ /**
+ * Gives the value of the {@link ValueParam} corresponding to the given key
+ * @param params the list of initial parameters from which we want to extract the {@link ValueParam}
+ * @param parameterKey the name of the {@link ValueParam} that we are looking for
+ * @return the value if it exists, null otherwise
+ */
+ private static String getValueParam(InitParams params, String parameterKey)
+ {
+ try
+ {
+ return params.getValueParam(parameterKey).getValue().trim();
+ }
+ catch (NullPointerException e)
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Gives the {@link URL} corresponding to the location of the JGroups configuration
+ * @param params the initial parameters from which we extract the parameter
+ * <code>PARAM_JGROUPS_CONFIG</code>
+ * @param configManager the configuration manager used to get the {@link URL} corresponding
+ * to the path given in the configuration of the RPCServiceImpl
+ * @return The {@link URL} corresponding to the location of the JGroups configuration,
+ * it will throw {@link RuntimeException} otherwise since it is a mandatory configuration.
+ */
+ private static URL getProperties(InitParams params, ConfigurationManager configManager)
+ {
+ String configPath = getValueParam(params, PARAM_JGROUPS_CONFIG);
+ if (configPath == null)
+ {
+ throw new IllegalArgumentException("The parameter '" + PARAM_JGROUPS_CONFIG
+ + "' of RPCServiceImpl is mandatory");
+ }
+ URL properties;
+ try
+ {
+ properties = configManager.getResource(configPath);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Cannot find the JGroups configuration at " + configPath, e);
+ }
+ if (properties == null)
+ {
+ throw new IllegalArgumentException("Cannot find the JGroups configuration at " + configPath);
+ }
+ return properties;
+ }
+
+ /**
+ * Gives the name of the cluster that will be able to support several portal containers
+ * since the name will be post fixed with "-${container-name}"
+ * @param ctx the context from which we extract the name of the container
+ * @param params the list of initial parameters from which we get the value of the parameter
+ * <code>PARAM_CLUSTER_NAME</code> if it exists otherwise the value will be "RPCService-Cluster"
+ */
+ private static String getClusterName(ExoContainerContext ctx, InitParams params)
+ {
+ String clusterName = getValueParam(params, PARAM_CLUSTER_NAME);
+ if (clusterName == null)
+ {
+ clusterName = CLUSTER_NAME;
+ }
+ return clusterName += "-" + ctx.getName();
+ }
+
+ /**
+ * Execute a privilege action
+ */
+ private static <E> E doPriviledgedExceptionAction(PrivilegedExceptionAction<E> action) throws ChannelException
+ {
+ try
+ {
+ return AccessController.doPrivileged(action);
+ }
+ catch (PrivilegedActionException pae)
+ {
+ Throwable cause = pae.getCause();
+ if (cause instanceof ChannelException)
+ {
+ throw (ChannelException)cause;
+ }
+ else if (cause instanceof RuntimeException)
+ {
+ throw (RuntimeException)cause;
+ }
+ else
+ {
+ throw new RuntimeException(cause);
+ }
+ }
+ }
+
+ /**
+ * This intern class will be used to
+ */
+ public static class MessageBody implements Externalizable
+ {
+ /**
+ * The Id of the command to execute
+ */
+ private String commandId;
+
+ /**
+ * The list of parameters;
+ */
+ private Serializable[] args;
+
+ public MessageBody()
+ {
+ }
+
+ public MessageBody(String commandId, Serializable[] args)
+ {
+ this.commandId = commandId;
+ this.args = args;
+ }
+
+ public String getCommandId()
+ {
+ return commandId;
+ }
+
+ public Serializable[] getArgs()
+ {
+ return args;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+ {
+ this.commandId = in.readUTF();
+ int size = in.readInt();
+ if (size == -1)
+ {
+ this.args = null;
+ }
+ else
+ {
+ this.args = new Serializable[size];
+ for (int i = 0; i < size; i++)
+ {
+ args[i] = (Serializable)in.readObject();
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void writeExternal(ObjectOutput out) throws IOException
+ {
+ out.writeUTF(commandId);
+ if (args == null)
+ {
+ out.writeInt(-1);
+ }
+ else
+ {
+ out.writeInt(args.length);
+ for (int i = 0; i < args.length; i++)
+ {
+ out.writeObject(args[i]);
+ }
+ }
+ }
+ }
+
+ /**
+ * All the potential states of the {@link RPCServiceImpl}
+ */
+ public enum State {
+ INITIALIZED, STARTED, STOPPED
+ }
+
+ public static class MemberHasLeftException extends RPCException
+ {
+
+ /**
+ * The serial version UID
+ */
+ private static final long serialVersionUID = 3558158913564367637L;
+
+ public MemberHasLeftException(String message)
+ {
+ super(message);
+ }
+ }
+}
Added: kernel/trunk/exo.kernel.component.common/src/test/java/org/exoplatform/services/rpc/impl/TestRPCServiceImpl.java
===================================================================
--- kernel/trunk/exo.kernel.component.common/src/test/java/org/exoplatform/services/rpc/impl/TestRPCServiceImpl.java (rev 0)
+++ kernel/trunk/exo.kernel.component.common/src/test/java/org/exoplatform/services/rpc/impl/TestRPCServiceImpl.java 2010-10-06 14:10:44 UTC (rev 3252)
@@ -0,0 +1,1062 @@
+/*
+ * Copyright (C) 2010 eXo Platform SAS.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.exoplatform.services.rpc.impl;
+
+import org.exoplatform.container.PortalContainer;
+import org.exoplatform.container.configuration.ConfigurationManager;
+import org.exoplatform.container.xml.InitParams;
+import org.exoplatform.container.xml.ValueParam;
+import org.exoplatform.services.rpc.RPCException;
+import org.exoplatform.services.rpc.RemoteCommand;
+import org.exoplatform.services.rpc.SingleMethodCallCommand;
+import org.exoplatform.services.rpc.impl.RPCServiceImpl.MemberHasLeftException;
+import org.exoplatform.test.BasicTestCase;
+import org.jgroups.Address;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Vector;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * This is the unit test class for the service {@link RPCServiceImpl}
+ *
+ * @author <a href="mailto:nicolas.filotto@exoplatform.com">Nicolas Filotto</a>
+ * @version $Id$
+ *
+ */
+public class TestRPCServiceImpl extends BasicTestCase
+{
+ private PortalContainer container;
+ private ConfigurationManager configManager;
+
+ public void setUp() throws Exception
+ {
+ container = PortalContainer.getInstance();
+ configManager = (ConfigurationManager)container.getComponentInstanceOfType(ConfigurationManager.class);
+ }
+
+ public void testParameters()
+ {
+ InitParams params = null;
+ try
+ {
+ new RPCServiceImpl(container.getContext(), params, configManager);
+ fail("We expect a IllegalArgumentException since the jgroups config cannot be found");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // OK
+ }
+ params = new InitParams();
+ try
+ {
+ new RPCServiceImpl(container.getContext(), params, configManager);
+ fail("We expect a IllegalArgumentException since the jgroups config cannot be found");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // OK
+ }
+ ValueParam paramConf = new ValueParam();
+ paramConf.setName(RPCServiceImpl.PARAM_JGROUPS_CONFIG);
+ params.addParameter(paramConf);
+ try
+ {
+ new RPCServiceImpl(container.getContext(), params, configManager);
+ fail("We expect a IllegalArgumentException since the jgroups config cannot be found");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // OK
+ }
+ paramConf.setValue("fakePath");
+ try
+ {
+ new RPCServiceImpl(container.getContext(), params, configManager);
+ fail("We expect a IllegalArgumentException since the jgroups config cannot be found");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // OK
+ }
+ paramConf.setValue("jar:/conf/portal/udp.xml");
+ RPCServiceImpl service = null;
+ try
+ {
+ service = new RPCServiceImpl(container.getContext(), params, configManager);
+ assertEquals(RPCServiceImpl.DEFAULT_TIMEOUT, service.getDefaultTimeout());
+ assertEquals(RPCServiceImpl.CLUSTER_NAME + "-" + container.getContext().getName(), service.getClusterName());
+ }
+ finally
+ {
+ if (service != null)
+ {
+ service.stop();
+ }
+ }
+ ValueParam paramTimeout = new ValueParam();
+ paramTimeout.setName(RPCServiceImpl.PARAM_DEFAULT_TIMEOUT);
+ paramTimeout.setValue("fakeValue");
+ params.addParameter(paramTimeout);
+ try
+ {
+ new RPCServiceImpl(container.getContext(), params, configManager);
+ fail("We expect a NumberFormatException since the timeout is not properly set");
+ }
+ catch (NumberFormatException e)
+ {
+ // OK
+ }
+ paramTimeout.setValue("60");
+ try
+ {
+ service = new RPCServiceImpl(container.getContext(), params, configManager);
+ assertEquals(60, service.getDefaultTimeout());
+ assertEquals(RPCServiceImpl.CLUSTER_NAME + "-" + container.getContext().getName(), service.getClusterName());
+ }
+ finally
+ {
+ if (service != null)
+ {
+ service.stop();
+ }
+ }
+ ValueParam paramClusterName = new ValueParam();
+ paramClusterName.setName(RPCServiceImpl.PARAM_CLUSTER_NAME);
+ paramClusterName.setValue("MyName");
+ params.addParameter(paramClusterName);
+ try
+ {
+ service = new RPCServiceImpl(container.getContext(), params, configManager);
+ assertEquals(60, service.getDefaultTimeout());
+ assertEquals(paramClusterName.getValue() + "-" + container.getContext().getName(), service.getClusterName());
+ }
+ finally
+ {
+ if (service != null)
+ {
+ service.stop();
+ }
+ }
+ }
+
+ public void testStates() throws Exception
+ {
+ InitParams params = new InitParams();
+ ValueParam paramConf = new ValueParam();
+ paramConf.setName(RPCServiceImpl.PARAM_JGROUPS_CONFIG);
+ paramConf.setValue("jar:/conf/portal/udp.xml");
+ params.addParameter(paramConf);
+ RPCServiceImpl service = null;
+ RemoteCommand foo = new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "foo";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ return null;
+ }
+ };
+ try
+ {
+ service = new RPCServiceImpl(container.getContext(), params, configManager);
+
+ service.registerCommand(foo);
+ try
+ {
+ service.executeCommandOnAllNodes(foo, true);
+ fail("We expect a RPCException since the current state is not the expected one");
+ }
+ catch (RPCException e)
+ {
+ // OK
+ }
+ try
+ {
+ service.executeCommandOnAllNodes(foo, 10);
+ fail("We expect a RPCException since the current state is not the expected one");
+ }
+ catch (RPCException e)
+ {
+ // OK
+ }
+ try
+ {
+ service.executeCommandOnCoordinator(foo, true);
+ fail("We expect a RPCException since the current state is not the expected one");
+ }
+ catch (RPCException e)
+ {
+ // OK
+ }
+ try
+ {
+ service.executeCommandOnCoordinator(foo, 10);
+ fail("We expect a RPCException since the current state is not the expected one");
+ }
+ catch (RPCException e)
+ {
+ // OK
+ }
+ service.start();
+ service.executeCommandOnAllNodes(foo, true);
+ service.executeCommandOnAllNodes(foo, 10);
+ service.executeCommandOnCoordinator(foo, true);
+ service.executeCommandOnCoordinator(foo, 10);
+ }
+ finally
+ {
+ if (service != null)
+ {
+ service.stop();
+ }
+ }
+ try
+ {
+ service.executeCommandOnAllNodes(foo, true);
+ fail("We expect a RPCException since the current state is not the expected one");
+ }
+ catch (RPCException e)
+ {
+ // OK
+ }
+ try
+ {
+ service.executeCommandOnAllNodes(foo, 10);
+ fail("We expect a RPCException since the current state is not the expected one");
+ }
+ catch (RPCException e)
+ {
+ // OK
+ }
+ try
+ {
+ service.executeCommandOnCoordinator(foo, true);
+ fail("We expect a RPCException since the current state is not the expected one");
+ }
+ catch (RPCException e)
+ {
+ // OK
+ }
+ try
+ {
+ service.executeCommandOnCoordinator(foo, 10);
+ fail("We expect a RPCException since the current state is not the expected one");
+ }
+ catch (RPCException e)
+ {
+ // OK
+ }
+ }
+
+ public void testCommands() throws Exception
+ {
+ InitParams params = new InitParams();
+ ValueParam paramConf = new ValueParam();
+ paramConf.setName(RPCServiceImpl.PARAM_JGROUPS_CONFIG);
+ paramConf.setValue("jar:/conf/portal/udp.xml");
+ params.addParameter(paramConf);
+ RPCServiceImpl service = null;
+ try
+ {
+ service = new RPCServiceImpl(container.getContext(), params, configManager);
+ RemoteCommand fake = new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "fake";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ return null;
+ }
+ };
+ RemoteCommand fake2 = new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "fake2";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ return null;
+ }
+ };
+ RemoteCommand fake2_Unregistered = new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "fake2";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ return null;
+ }
+ };
+ service.registerCommand(fake2);
+ RemoteCommand Exception = new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "Exception";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ throw new Exception("MyException");
+ }
+ };
+ service.registerCommand(Exception);
+ RemoteCommand Error = new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "Error";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ throw new Error("MyError");
+ }
+ } ;
+ service.registerCommand(Error);
+ RemoteCommand StringValue = new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "StringValue";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ return "OK";
+ }
+ };
+ service.registerCommand(StringValue);
+ RemoteCommand NullValue = new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "NullValue";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ return null;
+ }
+ };
+ service.registerCommand(NullValue);
+ RemoteCommand LongTask = new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "LongTask";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ Thread.sleep(2000);
+ return null;
+ }
+ };
+ service.registerCommand(LongTask);
+ service.start();
+ try
+ {
+ service.executeCommandOnAllNodes(fake, true);
+ fail("We expect a RPCException since the command is unknown");
+ }
+ catch (RPCException e)
+ {
+ // OK
+ }
+ try
+ {
+ service.executeCommandOnCoordinator(fake, true);
+ fail("We expect a RPCException since the command is unknown");
+ }
+ catch (RPCException e)
+ {
+ // OK
+ }
+ try
+ {
+ service.executeCommandOnAllNodes(fake2_Unregistered, true);
+ fail("We expect a RPCException since the command is unknown");
+ }
+ catch (RPCException e)
+ {
+ // OK
+ }
+ try
+ {
+ service.executeCommandOnCoordinator(fake2_Unregistered, true);
+ fail("We expect a RPCException since the command is unknown");
+ }
+ catch (RPCException e)
+ {
+ // OK
+ }
+ List<Object> result;
+ result = service.executeCommandOnAllNodes(Exception, true);
+ assertTrue(result != null && result.size() == 1);
+ assertTrue("We expect a RPCException since one node could not execute the command", result.get(0) instanceof RPCException);
+ try
+ {
+ service.executeCommandOnCoordinator(Exception, true);
+ fail("We expect a RPCException since one node could not execute the command");
+ }
+ catch (RPCException e)
+ {
+ // OK
+ }
+ result = service.executeCommandOnAllNodes(Error, true);
+ assertTrue(result != null && result.size() == 1);
+ assertTrue("We expect a RPCException since one node could not execute the command", result.get(0) instanceof RPCException);
+ try
+ {
+ service.executeCommandOnCoordinator(Error, true);
+ fail("We expect a RPCException since one node could not execute the command");
+ }
+ catch (RPCException e)
+ {
+ // OK
+ }
+ result = service.executeCommandOnAllNodes(LongTask, true);
+ assertNotNull(result);
+ assertTrue(result.size() == 1);
+ assertNull(result.get(0));
+ Object o = service.executeCommandOnCoordinator(LongTask, true);
+ assertNull(o);
+ result = service.executeCommandOnAllNodes(LongTask, 1000);
+ assertNotNull(result);
+ assertTrue(result.size() == 1);
+ assertTrue("We expect an RPCException due to a Replication Timeout", result.get(0) instanceof RPCException);
+ try
+ {
+ service.executeCommandOnCoordinator(LongTask, 1000);
+ fail("We expect an RPCException due to a Replication Timeout");
+ }
+ catch (RPCException e)
+ {
+ // OK
+ }
+ result = service.executeCommandOnAllNodes(LongTask, false);
+ assertNotNull(result);
+ assertTrue(result.isEmpty());
+ assertNull(service.executeCommandOnCoordinator(LongTask, false));
+
+ result = service.executeCommandOnAllNodes(StringValue, true);
+ assertNotNull(result);
+ assertTrue(result.size() == 1);
+ assertEquals("OK", result.get(0));
+ o = service.executeCommandOnCoordinator(StringValue, true);
+ assertEquals("OK", o);
+ result = service.executeCommandOnAllNodes(NullValue, true);
+ assertNotNull(result);
+ assertTrue(result.size() == 1);
+ assertNull(result.get(0));
+ o = service.executeCommandOnCoordinator(NullValue, true);
+ assertNull(o);
+ }
+ finally
+ {
+ if (service != null)
+ {
+ service.stop();
+ }
+ }
+ }
+
+ public void testSeveralNodes() throws Exception
+ {
+ InitParams params = new InitParams();
+ ValueParam paramConf = new ValueParam();
+ paramConf.setName(RPCServiceImpl.PARAM_JGROUPS_CONFIG);
+ paramConf.setValue("jar:/conf/portal/udp.xml");
+ params.addParameter(paramConf);
+ RPCServiceImpl service1 = null, service2 = null;
+ try
+ {
+ service1 = new RPCServiceImpl(container.getContext(), params, configManager);
+ service2 = new RPCServiceImpl(container.getContext(), params, configManager);
+ RemoteCommand CmdUnknownOnNode2 = new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "CmdUnknownOnNode2";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ return "OK";
+ }
+ };
+ service1.registerCommand(CmdUnknownOnNode2);
+ RemoteCommand ExceptionOnNode2 = new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "ExceptionOnNode2";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ return "OK";
+ }
+ };
+ service1.registerCommand(ExceptionOnNode2);
+ RemoteCommand ErrorOnNode2 = new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "ErrorOnNode2";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ return "OK";
+ }
+ };
+ service1.registerCommand(ErrorOnNode2);
+
+ RemoteCommand LongTaskOnNode2 = new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "LongTaskOnNode2";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ return "OK";
+ }
+ };
+ service1.registerCommand(LongTaskOnNode2);
+ service1.registerCommand(new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "LongTask";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ Thread.sleep(20000);
+ return "OldCoordinator";
+ }
+ });
+ service1.registerCommand(new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "OK";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ return "OK";
+ }
+ });
+ service2.registerCommand(new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "ExceptionOnNode2";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ throw new Exception("MyException");
+ }
+ });
+ service2.registerCommand(new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "ErrorOnNode2";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ throw new Error("MyError");
+ }
+ });
+ service2.registerCommand(new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "LongTaskOnNode2";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ Thread.sleep(2000);
+ return null;
+ }
+ });
+ RemoteCommand OK = new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "OK";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ return "OK";
+ }
+ };
+ service2.registerCommand(OK);
+ final RemoteCommand LongTask = new RemoteCommand()
+ {
+
+ public String getId()
+ {
+ return "LongTask";
+ }
+
+ public String execute(Serializable[] args) throws Throwable
+ {
+ return "NewCoordinator";
+ }
+ };
+ service2.registerCommand(LongTask);
+ service1.start();
+ service2.start();
+ List<Object> result;
+ Object o;
+ result = service1.executeCommandOnAllNodes(CmdUnknownOnNode2, true);
+ assertTrue(result != null && result.size() == 2);
+ assertEquals("OK", result.get(0));
+ assertTrue("We expect a RPCException since the command is unknown on node 2", result.get(1) instanceof RPCException);
+ o = service1.executeCommandOnCoordinator(CmdUnknownOnNode2, true);
+ assertEquals("OK", o);
+
+ result = service1.executeCommandOnAllNodes(ExceptionOnNode2, true);
+ assertTrue(result != null && result.size() == 2);
+ assertEquals("OK", result.get(0));
+ assertTrue("We expect a RPCException since the command fails on node 2", result.get(1) instanceof RPCException);
+ o = service1.executeCommandOnCoordinator(ExceptionOnNode2, true);
+ assertEquals("OK", o);
+
+ result = service1.executeCommandOnAllNodes(ErrorOnNode2, true);
+ assertTrue(result != null && result.size() == 2);
+ assertEquals("OK", result.get(0));
+ assertTrue("We expect a RPCException since the command fails on node 2", result.get(1) instanceof RPCException);
+ o = service1.executeCommandOnCoordinator(ErrorOnNode2, true);
+ assertEquals("OK", o);
+
+ result = service1.executeCommandOnAllNodes(LongTaskOnNode2, 1000);
+ assertNotNull(result);
+ assertTrue(result.size() == 2);
+ assertEquals("OK", result.get(0));
+ assertTrue("We expect an RPCException due to a Replication Timeout", result.get(1) instanceof RPCException);
+ o = service1.executeCommandOnCoordinator(LongTaskOnNode2, 1000);
+ assertEquals("OK", o);
+
+ Vector<Address> allMembers = service1.members;
+ Vector<Address> coordinatorOnly = new Vector<Address>(1);
+ coordinatorOnly.add(service1.coordinator);
+
+ final RPCServiceImpl service = service2;
+ final AtomicReference<Throwable> error = new AtomicReference<Throwable>();
+ final CountDownLatch doneSignal = new CountDownLatch(1);
+ Thread t = new Thread()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ Object o = service.executeCommandOnCoordinator(LongTask, true);
+ assertEquals("NewCoordinator", o);
+ }
+ catch (Throwable e)
+ {
+ error.set(e);
+ }
+ finally
+ {
+ doneSignal.countDown();
+ }
+ }
+ };
+ t.start();
+ service1.stop();
+ doneSignal.await();
+ assertNull(error.get() != null ? error.get().getMessage() : "", error.get());
+ result = service2.excecuteCommand(allMembers, OK, true, 0);
+ assertNotNull(result);
+ assertTrue(result.size() == 2);
+ assertTrue("We expect an RPCException due to a member that has left", result.get(0) instanceof MemberHasLeftException);
+ assertEquals("OK", result.get(1));
+ result = service2.excecuteCommand(coordinatorOnly, OK, true, 0);
+ assertNotNull(result);
+ assertTrue(result.size() == 1);
+ assertTrue("We expect an RPCException due to a member that has left", result.get(0) instanceof MemberHasLeftException);
+ }
+ finally
+ {
+ if (service1 != null)
+ {
+ service1.stop();
+ }
+ if (service2 != null)
+ {
+ service2.stop();
+ }
+ }
+ }
+
+ public void testSingleMethodCallCommand() throws Exception
+ {
+ try
+ {
+ new SingleMethodCallCommand(null, null);
+ fail("we expect an IllegalArgumentException");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // OK
+ }
+ MyService myService = new MyService();
+ try
+ {
+ new SingleMethodCallCommand(myService, null);
+ fail("we expect an IllegalArgumentException");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // OK
+ }
+ try
+ {
+ new SingleMethodCallCommand(myService, "foo");
+ fail("we expect an NoSuchMethodException");
+ }
+ catch (NoSuchMethodException e)
+ {
+ // OK
+ }
+ try
+ {
+ new SingleMethodCallCommand(myService, "getPrivateName");
+ fail("we expect an IllegalArgumentException since only the public methods are allowed");
+ }
+ catch (IllegalArgumentException e)
+ {
+ // OK
+ }
+ InitParams params = new InitParams();
+ ValueParam paramConf = new ValueParam();
+ paramConf.setName(RPCServiceImpl.PARAM_JGROUPS_CONFIG);
+ paramConf.setValue("jar:/conf/portal/udp.xml");
+ params.addParameter(paramConf);
+ RPCServiceImpl service = null;
+ try
+ {
+ service = new RPCServiceImpl(container.getContext(), params, configManager);
+ RemoteCommand getName = service.registerCommand(new SingleMethodCallCommand(myService, "getName"));
+ RemoteCommand add = service.registerCommand(new SingleMethodCallCommand(myService, "add", int.class));
+ RemoteCommand evaluate1 = service.registerCommand(new SingleMethodCallCommand(myService, "evaluate", int[].class));
+ RemoteCommand evaluate2 = service.registerCommand(new SingleMethodCallCommand(myService, "evaluate", List.class));
+ RemoteCommand total1 = service.registerCommand(new SingleMethodCallCommand(myService, "total", int.class));
+ RemoteCommand total2 = service.registerCommand(new SingleMethodCallCommand(myService, "total", int.class, int.class));
+ RemoteCommand total3 = service.registerCommand(new SingleMethodCallCommand(myService, "total", int[].class));
+ RemoteCommand total4 = service.registerCommand(new SingleMethodCallCommand(myService, "total", String.class, long.class, int[].class));
+ RemoteCommand testTypes1 = service.registerCommand(new SingleMethodCallCommand(myService, "testTypes", String[].class));
+ RemoteCommand testTypes2 = service.registerCommand(new SingleMethodCallCommand(myService, "testTypes", int[].class));
+ RemoteCommand testTypes3 = service.registerCommand(new SingleMethodCallCommand(myService, "testTypes", long[].class));
+ RemoteCommand testTypes4 = service.registerCommand(new SingleMethodCallCommand(myService, "testTypes", byte[].class));
+ RemoteCommand testTypes5 = service.registerCommand(new SingleMethodCallCommand(myService, "testTypes", short[].class));
+ RemoteCommand testTypes6 = service.registerCommand(new SingleMethodCallCommand(myService, "testTypes", char[].class));
+ RemoteCommand testTypes7 = service.registerCommand(new SingleMethodCallCommand(myService, "testTypes", double[].class));
+ RemoteCommand testTypes8 = service.registerCommand(new SingleMethodCallCommand(myService, "testTypes", float[].class));
+ RemoteCommand testTypes9 = service.registerCommand(new SingleMethodCallCommand(myService, "testTypes", boolean[].class));
+
+ service.start();
+ List<Object> result;
+
+ assertEquals("name", service.executeCommandOnCoordinator(getName, true));
+ result = service.executeCommandOnAllNodes(getName, true);
+ assertTrue(result != null && result.size() == 1);
+ assertEquals("name", result.get(0));
+
+ assertEquals(10, service.executeCommandOnCoordinator(add, true, 10));
+ result = service.executeCommandOnAllNodes(add, true, 10);
+ assertTrue(result != null && result.size() == 1);
+ assertEquals(20, result.get(0));
+
+ assertEquals(100, service.executeCommandOnCoordinator(evaluate1, true, new int[]{10, 10, 10, 30, 40}));
+ result = service.executeCommandOnAllNodes(evaluate1, true, new int[]{10, 10, 10, 30, 40});
+ assertTrue(result != null && result.size() == 1);
+ assertEquals(100, result.get(0));
+
+ List<Integer> values = new ArrayList<Integer>();
+ values.add(10);
+ values.add(10);
+ values.add(10);
+ values.add(30);
+ values.add(40);
+ assertEquals(100, service.executeCommandOnCoordinator(evaluate2, true, (Serializable)values));
+ result = service.executeCommandOnAllNodes(evaluate2, true, (Serializable)values);
+ assertTrue(result != null && result.size() == 1);
+ assertEquals(100, result.get(0));
+
+ assertEquals(10, service.executeCommandOnCoordinator(total1, true, 10));
+ result = service.executeCommandOnAllNodes(total1, true, 10);
+ assertTrue(result != null && result.size() == 1);
+ assertEquals(10, result.get(0));
+
+ assertEquals(20, service.executeCommandOnCoordinator(total2, true, 10, 10));
+ result = service.executeCommandOnAllNodes(total2, true, 10, 10);
+ assertTrue(result != null && result.size() == 1);
+ assertEquals(20, result.get(0));
+
+ assertEquals(100, service.executeCommandOnCoordinator(total3, true, new int[]{10, 10, 10, 30, 40}));
+ result = service.executeCommandOnAllNodes(total3, true, new int[]{10, 10, 10, 30, 40});
+ assertTrue(result != null && result.size() == 1);
+ assertEquals(100, result.get(0));
+
+ assertEquals(100, service.executeCommandOnCoordinator(total4, true, "foo", 50, new int[]{10, 10, 10, 30, 40}));
+ result = service.executeCommandOnAllNodes(total4, true, "foo", 50, new int[]{10, 10, 10, 30, 40});
+ assertTrue(result != null && result.size() == 1);
+ assertEquals(100, result.get(0));
+
+ assertEquals(0, service.executeCommandOnCoordinator(total4, true, "foo", 50, null));
+ result = service.executeCommandOnAllNodes(total4, true, "foo", 50, null);
+ assertTrue(result != null && result.size() == 1);
+ assertEquals(0, result.get(0));
+
+ try
+ {
+ service.executeCommandOnCoordinator(total4, true, "foo", 50);
+ fail("We expect a RPCException since the list of arguments mismatch with what is expected");
+ }
+ catch (RPCException e)
+ {
+ // OK
+ }
+ result = service.executeCommandOnAllNodes(total4, true, "foo", 50);
+ assertTrue(result != null && result.size() == 1);
+ assertTrue("We expect a RPCException since the list of arguments mismatch with what is expected", result.get(0) instanceof RPCException);
+
+ assertEquals("foo", service.executeCommandOnCoordinator(testTypes1, true, (Serializable)new String[]{"foo"}));
+ result = service.executeCommandOnAllNodes(testTypes1, true, (Serializable)new String[]{"foo"});
+ assertTrue(result != null && result.size() == 1);
+ assertEquals("foo", result.get(0));
+
+ assertEquals(10, service.executeCommandOnCoordinator(testTypes2, true, new int[]{10}));
+ result = service.executeCommandOnAllNodes(testTypes2, true, new int[]{10});
+ assertTrue(result != null && result.size() == 1);
+ assertEquals(10, result.get(0));
+
+ assertEquals(11L, service.executeCommandOnCoordinator(testTypes3, true, new long[]{10}));
+ result = service.executeCommandOnAllNodes(testTypes3, true, new long[]{10});
+ assertTrue(result != null && result.size() == 1);
+ assertEquals(11L, result.get(0));
+
+ assertEquals((byte)12, service.executeCommandOnCoordinator(testTypes4, true, new byte[]{10}));
+ result = service.executeCommandOnAllNodes(testTypes4, true, new byte[]{10});
+ assertTrue(result != null && result.size() == 1);
+ assertEquals((byte)12, result.get(0));
+
+ assertEquals((short)13, service.executeCommandOnCoordinator(testTypes5, true, new short[]{10}));
+ result = service.executeCommandOnAllNodes(testTypes5, true, new short[]{10});
+ assertTrue(result != null && result.size() == 1);
+ assertEquals((short)13, result.get(0));
+
+ assertEquals('a', service.executeCommandOnCoordinator(testTypes6, true, new char[]{'a'}));
+ result = service.executeCommandOnAllNodes(testTypes6, true, new char[]{'a'});
+ assertTrue(result != null && result.size() == 1);
+ assertEquals('a', result.get(0));
+
+ assertEquals(10.5, service.executeCommandOnCoordinator(testTypes7, true, new double[]{10}));
+ result = service.executeCommandOnAllNodes(testTypes7, true, new double[]{10});
+ assertTrue(result != null && result.size() == 1);
+ assertEquals(10.5, result.get(0));
+
+ assertEquals((float)11.5, service.executeCommandOnCoordinator(testTypes8, true, new float[]{10}));
+ result = service.executeCommandOnAllNodes(testTypes8, true, new float[]{10});
+ assertTrue(result != null && result.size() == 1);
+ assertEquals((float)11.5, result.get(0));
+
+ assertEquals(true, service.executeCommandOnCoordinator(testTypes9, true, new boolean[]{true}));
+ result = service.executeCommandOnAllNodes(testTypes9, true, new boolean[]{true});
+ assertTrue(result != null && result.size() == 1);
+ assertEquals(true, result.get(0));
+
+ }
+ finally
+ {
+ if (service != null)
+ {
+ service.stop();
+ }
+ }
+ }
+
+ public static class MyService
+ {
+ private int value = 0;
+
+ public int add(int i)
+ {
+ return value += i;
+ }
+
+ @SuppressWarnings("unused")
+ private String getPrivateName()
+ {
+ return "name";
+ }
+
+ public String getName()
+ {
+ return "name";
+ }
+
+ public int total(int i)
+ {
+ return i;
+ }
+
+ public int total(int i1, int i2)
+ {
+ return i1 + i2;
+ }
+
+ public int total(int... values)
+ {
+ int total = 0;
+ for (int i : values)
+ {
+ total += i;
+ }
+ return total;
+ }
+
+ public int total(String s, long l, int... values)
+ {
+ int total = 0;
+ if (values != null)
+ {
+ for (int i : values)
+ {
+ total += i;
+ }
+ }
+ return total;
+ }
+
+ public int evaluate(int[] values)
+ {
+ int total = 0;
+ for (int i : values)
+ {
+ total += i;
+ }
+ return total;
+ }
+
+ public int evaluate(List<Integer> values)
+ {
+ int total = 0;
+ for (int i : values)
+ {
+ total += i;
+ }
+ return total;
+ }
+
+ public String testTypes(String... values)
+ {
+ return values[0];
+ }
+
+ public boolean testTypes(boolean... values)
+ {
+ return values[0];
+ }
+
+ public char testTypes(char... values)
+ {
+ return values[0];
+ }
+
+ public double testTypes(double... values)
+ {
+ return values[0] + 0.5;
+ }
+
+ public float testTypes(float... values)
+ {
+ return (float)(values[0] + 1.5);
+ }
+
+ public int testTypes(int... values)
+ {
+ return values[0];
+ }
+
+ public long testTypes(long... values)
+ {
+ return values[0] + 1;
+ }
+
+ public byte testTypes(byte... values)
+ {
+ return (byte)(values[0] + 2);
+ }
+
+ public short testTypes(short... values)
+ {
+ return (short)(values[0] + 3);
+ }
+ }
+}
Added: kernel/trunk/exo.kernel.component.common/src/test/resources/conf/portal/udp.xml
===================================================================
--- kernel/trunk/exo.kernel.component.common/src/test/resources/conf/portal/udp.xml (rev 0)
+++ kernel/trunk/exo.kernel.component.common/src/test/resources/conf/portal/udp.xml 2010-10-06 14:10:44 UTC (rev 3252)
@@ -0,0 +1,64 @@
+<config>
+ <UDP
+ mcast_addr="${jgroups.udp.mcast_addr:228.10.10.10}"
+ mcast_port="${jgroups.udp.mcast_port:45588}"
+ tos="8"
+ ucast_recv_buf_size="20000000"
+ ucast_send_buf_size="640000"
+ mcast_recv_buf_size="25000000"
+ mcast_send_buf_size="640000"
+ loopback="false"
+ discard_incompatible_packets="true"
+ max_bundle_size="64000"
+ max_bundle_timeout="30"
+ use_incoming_packet_handler="true"
+ ip_ttl="${jgroups.udp.ip_ttl:2}"
+ enable_bundling="false"
+ enable_diagnostics="true"
+ thread_naming_pattern="cl"
+
+ use_concurrent_stack="true"
+
+ thread_pool.enabled="true"
+ thread_pool.min_threads="2"
+ thread_pool.max_threads="8"
+ thread_pool.keep_alive_time="5000"
+ thread_pool.queue_enabled="true"
+ thread_pool.queue_max_size="1000"
+ thread_pool.rejection_policy="discard"
+
+ oob_thread_pool.enabled="true"
+ oob_thread_pool.min_threads="1"
+ oob_thread_pool.max_threads="8"
+ oob_thread_pool.keep_alive_time="5000"
+ oob_thread_pool.queue_enabled="false"
+ oob_thread_pool.queue_max_size="100"
+ oob_thread_pool.rejection_policy="Run" />
+
+ <PING timeout="2000"
+ num_initial_members="3"/>
+ <MERGE2 max_interval="30000"
+ min_interval="10000"/>
+ <FD_SOCK />
+ <FD timeout="10000" max_tries="5" shun="true" />
+ <VERIFY_SUSPECT timeout="1500" />
+ <BARRIER />
+ <pbcast.NAKACK use_stats_for_retransmission="false"
+ exponential_backoff="150"
+ use_mcast_xmit="true" gc_lag="0"
+ retransmit_timeout="50,300,600,1200"
+ discard_delivered_msgs="true"/>
+ <UNICAST timeout="300,600,1200" />
+ <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
+ max_bytes="1000000"/>
+ <VIEW_SYNC avg_send_interval="60000" />
+ <pbcast.GMS print_local_addr="true" join_timeout="3000"
+ shun="false"
+ view_bundling="true"/>
+ <FC max_credits="500000"
+ min_threshold="0.20"/>
+ <FRAG2 frag_size="60000" />
+ <!--pbcast.STREAMING_STATE_TRANSFER /-->
+ <pbcast.STATE_TRANSFER />
+ <!-- pbcast.FLUSH /-->
+</config>
15 years, 9 months
exo-jcr SVN: r3251 - in ws/trunk: exo.ws.rest.core/src/main/java/org/exoplatform/services/rest/impl/provider and 1 other directories.
by do-not-reply@jboss.org
Author: aparfonov
Date: 2010-10-06 05:31:29 -0400 (Wed, 06 Oct 2010)
New Revision: 3251
Modified:
ws/trunk/exo.ws.frameworks.json/src/main/java/org/exoplatform/ws/frameworks/json/impl/JsonGeneratorImpl.java
ws/trunk/exo.ws.rest.core/src/main/java/org/exoplatform/services/rest/impl/provider/JsonEntityProvider.java
ws/trunk/exo.ws.rest.core/src/test/java/org/exoplatform/services/rest/impl/provider/JsonEntityTest.java
Log:
EXOJCR-992
Modified: ws/trunk/exo.ws.frameworks.json/src/main/java/org/exoplatform/ws/frameworks/json/impl/JsonGeneratorImpl.java
===================================================================
--- ws/trunk/exo.ws.frameworks.json/src/main/java/org/exoplatform/ws/frameworks/json/impl/JsonGeneratorImpl.java 2010-10-06 07:48:31 UTC (rev 3250)
+++ ws/trunk/exo.ws.frameworks.json/src/main/java/org/exoplatform/ws/frameworks/json/impl/JsonGeneratorImpl.java 2010-10-06 09:31:29 UTC (rev 3251)
@@ -29,6 +29,7 @@
import org.exoplatform.ws.frameworks.json.value.impl.ObjectValue;
import org.exoplatform.ws.frameworks.json.value.impl.StringValue;
+import java.io.StringReader;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -114,6 +115,22 @@
}
/**
+ * Create JSON object from specified string imply it is JSON object in String
+ * format.
+ *
+ * @param s source string
+ * @return JSON representation of map
+ * @throws JsonException if map can't be transformed in JSON representation
+ */
+ public JsonValue createJsonObjectFromString(String s) throws JsonException
+ {
+ JsonParserImpl parser = new JsonParserImpl();
+ JsonDefaultHandler handler = new JsonDefaultHandler();
+ parser.parse(new StringReader(s), handler);
+ return handler.getJsonObject();
+ }
+
+ /**
* Create JSON object from specified object. Object must be conform with java
* bean structure.
*
Modified: ws/trunk/exo.ws.rest.core/src/main/java/org/exoplatform/services/rest/impl/provider/JsonEntityProvider.java
===================================================================
--- ws/trunk/exo.ws.rest.core/src/main/java/org/exoplatform/services/rest/impl/provider/JsonEntityProvider.java 2010-10-06 07:48:31 UTC (rev 3250)
+++ ws/trunk/exo.ws.rest.core/src/main/java/org/exoplatform/services/rest/impl/provider/JsonEntityProvider.java 2010-10-06 09:31:29 UTC (rev 3251)
@@ -29,19 +29,27 @@
import org.exoplatform.ws.frameworks.json.impl.JsonUtils.Types;
import org.exoplatform.ws.frameworks.json.value.JsonValue;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.Reader;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Map;
+import javax.activation.DataSource;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.StreamingOutput;
import javax.ws.rs.ext.Provider;
+import javax.xml.bind.JAXBElement;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stream.StreamSource;
/**
* @author <a href="mailto:andrew00x@gmail.com">Andrey Parfonov</a>
@@ -60,13 +68,30 @@
// Or probably enough check only content type 'application/json'
// and if this content type set trust it and try parse/write
+ /** Do not process via JSON "known" JAX-RS types. */
+ private static final Class<?>[] IGNORED =
+ new Class<?>[]{byte[].class, DataSource.class, DOMSource.class, File.class, InputStream.class, JAXBElement.class,
+ MultivaluedMap.class, Reader.class, SAXSource.class, StreamingOutput.class, StreamSource.class, String.class};
+
+ private static boolean isIgnored(Class<?> type)
+ {
+ for (Class<?> c : IGNORED)
+ {
+ if (c.isAssignableFrom(type))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* {@inheritDoc}
*/
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType)
{
- // say as support all objects, see _TODO_ above
- return Object.class.isAssignableFrom(type);
+ // return Object.class.isAssignableFrom(type);
+ return !isIgnored(type);
}
/**
@@ -124,8 +149,8 @@
*/
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType)
{
- // say as support all objects, see _TODO_ above
- return Object.class.isAssignableFrom(type);
+ // return Object.class.isAssignableFrom(type);
+ return !isIgnored(type);
}
/**
Modified: ws/trunk/exo.ws.rest.core/src/test/java/org/exoplatform/services/rest/impl/provider/JsonEntityTest.java
===================================================================
--- ws/trunk/exo.ws.rest.core/src/test/java/org/exoplatform/services/rest/impl/provider/JsonEntityTest.java 2010-10-06 07:48:31 UTC (rev 3250)
+++ ws/trunk/exo.ws.rest.core/src/test/java/org/exoplatform/services/rest/impl/provider/JsonEntityTest.java 2010-10-06 09:31:29 UTC (rev 3251)
@@ -40,7 +40,9 @@
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
/**
* @author <a href="mailto:andrew00x@gmail.com">Andrey Parfonov</a>
@@ -111,6 +113,17 @@
}
@Path("/")
+ public static class ResourceString
+ {
+ @POST
+ @Consumes("application/json")
+ public void m1(String b)
+ {
+ assertEquals(jsonBook, b);
+ }
+ }
+
+ @Path("/")
public static class ResourceBook2
{
@GET
@@ -228,6 +241,33 @@
}
}
+ @Path("/")
+ public static class ResourceString2
+ {
+ @GET
+ @Produces("application/json")
+ public String m1()
+ {
+ return jsonBook;
+ }
+
+ @POST
+ public Response m2()
+ {
+ return Response.ok(jsonBook).type(MediaType.APPLICATION_JSON).build();
+ }
+ }
+
+ private static String jsonBook = "{\"title\":\"Hamlet\", \"author\":\"William Shakespeare\", \"sendByPost\":true}";
+
+ private static String jsonArray =
+ "[{\"title\":\"Hamlet\", \"author\":\"William Shakespeare\", \"sendByPost\":true},"
+ + "{\"title\":\"Collected Stories\", \"author\":\"Gabriel Garcia Marquez\", \"sendByPost\":true}]";
+
+ private static String jsonMap =
+ "{\"12345\":{\"title\":\"Hamlet\", \"author\":\"William Shakespeare\", \"sendByPost\":true},"
+ + "\"54321\":{\"title\":\"Collected Stories\", \"author\":\"Gabriel Garcia Marquez\", \"sendByPost\":true}}";
+
private byte[] jsonBookData;
private byte[] jsonArrayData;
@@ -237,16 +277,9 @@
public void setUp() throws Exception
{
super.setUp();
- jsonBookData =
- ("{\"title\":\"Hamlet\", \"author\":\"William Shakespeare\", \"sendByPost\":true}").getBytes("UTF-8");
- jsonArrayData =
- ("[{\"title\":\"Hamlet\", \"author\":\"William Shakespeare\", \"sendByPost\":true},"
- + "{\"title\":\"Collected Stories\", \"author\":\"Gabriel Garcia Marquez\", \"sendByPost\":true}]")
- .getBytes("UTF-8");
- jsonMapData =
- ("{\"12345\":{\"title\":\"Hamlet\", \"author\":\"William Shakespeare\", \"sendByPost\":true},"
- + "\"54321\":{\"title\":\"Collected Stories\", \"author\":\"Gabriel Garcia Marquez\", \"sendByPost\":true}}")
- .getBytes("UTF-8");
+ jsonBookData = jsonBook.getBytes("UTF-8");
+ jsonArrayData = jsonArray.getBytes("UTF-8");
+ jsonMapData = jsonMap.getBytes("UTF-8");
}
public void testJsonEntityBean() throws Exception
@@ -299,6 +332,17 @@
unregistry(r1);
}
+ public void testJsonEntityString() throws Exception
+ {
+ ResourceString r1 = new ResourceString();
+ registry(r1);
+ MultivaluedMap<String, String> h = new MultivaluedMapImpl();
+ h.putSingle("content-type", "application/json");
+ h.putSingle("content-length", "" + jsonBookData.length);
+ assertEquals(204, launcher.service("POST", "/", "", h, jsonBookData, null).getStatus());
+ unregistry(r1);
+ }
+
public void testJsonReturnBean() throws Exception
{
ResourceBook2 r2 = new ResourceBook2();
@@ -472,4 +516,30 @@
unregistry(r2);
}
+
+ public void testJsonReturnString() throws Exception
+ {
+ ResourceString2 r2 = new ResourceString2();
+ registry(r2);
+ MultivaluedMap<String, String> h = new MultivaluedMapImpl();
+ h.putSingle("accept", "application/json");
+ ByteArrayContainerResponseWriter writer = new ByteArrayContainerResponseWriter();
+
+ // ResourceString2#m1()
+ ContainerResponse response = launcher.service("GET", "/", "", h, null, writer, null);
+ assertEquals(200, response.getStatus());
+ assertEquals("application/json", response.getContentType().toString());
+ assertEquals(jsonBook, response.getEntity());
+ //System.out.println("string: " + new String(writer.getBody()));
+
+ // ResourceString2#m2()
+ writer.reset();
+ response = launcher.service("POST", "/", "", h, null, writer, null);
+ assertEquals(200, response.getStatus());
+ assertEquals("application/json", response.getContentType().toString());
+ assertEquals(jsonBook, response.getEntity());
+ //System.out.println("string: " + new String(writer.getBody()));
+
+ unregistry(r2);
+ }
}
15 years, 9 months