Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Rich Client Platform (RCP) » How to connect from an RCP Client via RMI to an EJB (over Http)
How to connect from an RCP Client via RMI to an EJB (over Http) [message #443166] Tue, 24 January 2006 07:47 Go to next message
Eclipse User
Originally posted by: rene.huguet.besonet.ch

Hi there
We like to use rcp as client platform an the business processes on a JBoss AS (client and server separated).

We have the problem to connect from the plug-in via HttpNamingContextFactory (RMI over Http)
to the EJB on the JBoss AS.

When connecting with a JavaClient (not plug-in) the connection to the EJB works fine.
When connecting from a RCP Plugin we get the exception: (thrown in ObjectInputStream readObject())

Caused by: java.lang.ClassNotFoundException: com.prodega.ejbtest.interfaces.BenutzerManagerHome (no security manager: RMI class loader disabled)
at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.ja va:531)
at java.rmi.server.RMIClassLoader$2.loadProxyClass(RMIClassLoad er.java:628)
at java.rmi.server.RMIClassLoader.loadProxyClass(RMIClassLoader .java:294)
at sun.rmi.server.MarshalInputStream.resolveProxyClass(MarshalI nputStream.java:238)
at java.io.ObjectInputStream.readProxyDesc(ObjectInputStream.ja va:1494)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.ja va:1457)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStre am.java:1693)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java :1299)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java: 339)
at java.rmi.MarshalledObject.get(MarshalledObject.java:135)
at org.jnp.interfaces.MarshalledValuePair.get(MarshalledValuePa ir.java:57)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:6 37)
... 33 more

<b>The jndi.properties:</b>

java.naming.factory.initial=org.jboss.naming.HttpNamingConte xtFactory
java.naming.provider.url=http://localhost:8080/invoker/JNDIFactory
java.naming.security.authentication=none (tested with and without this statement)

<b>The Java Code</b> (Exception in statement: <b>Object ref = context.lookup("ejb/BenutzerManager");</b> ):

Context context = new InitialContext();
context.getEnvironment();
Object ref = context.lookup("ejb/BenutzerManager");
BenutzerManagerHome home = (BenutzerManagerHome) PortableRemoteObject.narrow(ref, BenutzerManagerHome.class);
BenutzerManager bean = home.create();

<b>JBoss Security Policy</b> (server.policy file on JBoss AS): //

grant {
// Allow everything for now
permission java.security.AllPermission;
};


As mentioned above the EJB is deployed on the JBoss AS and works fine when calling from a JavaClient (with same Java Code).
What do i need more ????

Thanks in advance
René
Re: How to connect from an RCP Client via RMI to an EJB (over Http) [message #443192 is a reply to message #443166] Tue, 24 January 2006 08:53 Go to previous messageGo to next message
Stefan Langer is currently offline Stefan Langer
Messages: 236
Registered: July 2009
Senior Member
As the exception tells you, you need to set a security manager via
System.setSecurityManager! Be aware that you might need to set a policy
file for your RCP Client as well. I suggest for developement to grant
all permissions and take it from there.

Regards
Stefan

Rene Huguet wrote:
> Hi there
> We like to use rcp as client platform an the business processes on a JBoss AS (client and server separated).
>
> We have the problem to connect from the plug-in via HttpNamingContextFactory (RMI over Http)
> to the EJB on the JBoss AS.
>
> When connecting with a JavaClient (not plug-in) the connection to the EJB works fine.
> When connecting from a RCP Plugin we get the exception: (thrown in ObjectInputStream readObject())
>
> Caused by: java.lang.ClassNotFoundException: com.prodega.ejbtest.interfaces.BenutzerManagerHome (no security manager: RMI class loader disabled)
> at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.ja va:531)
> at java.rmi.server.RMIClassLoader$2.loadProxyClass(RMIClassLoad er.java:628)
> at java.rmi.server.RMIClassLoader.loadProxyClass(RMIClassLoader .java:294)
> at sun.rmi.server.MarshalInputStream.resolveProxyClass(MarshalI nputStream.java:238)
> at java.io.ObjectInputStream.readProxyDesc(ObjectInputStream.ja va:1494)
> at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.ja va:1457)
> at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStre am.java:1693)
> at java.io.ObjectInputStream.readObject0(ObjectInputStream.java :1299)
> at java.io.ObjectInputStream.readObject(ObjectInputStream.java: 339)
> at java.rmi.MarshalledObject.get(MarshalledObject.java:135)
> at org.jnp.interfaces.MarshalledValuePair.get(MarshalledValuePa ir.java:57)
> at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:6 37)
> ... 33 more
>
> <b>The jndi.properties:</b>
>
> java.naming.factory.initial=org.jboss.naming.HttpNamingConte xtFactory
> java.naming.provider.url=http://localhost:8080/invoker/JNDIFactory
> java.naming.security.authentication=none (tested with and without this statement)
>
> <b>The Java Code</b> (Exception in statement: <b>Object ref = context.lookup("ejb/BenutzerManager");</b> ):
>
> Context context = new InitialContext();
> context.getEnvironment();
> Object ref = context.lookup("ejb/BenutzerManager");
> BenutzerManagerHome home = (BenutzerManagerHome) PortableRemoteObject.narrow(ref, BenutzerManagerHome.class);
> BenutzerManager bean = home.create();
>
> <b>JBoss Security Policy</b> (server.policy file on JBoss AS): //
>
> grant {
> // Allow everything for now
> permission java.security.AllPermission;
> };
>
>
> As mentioned above the EJB is deployed on the JBoss AS and works fine when calling from a JavaClient (with same Java Code).
> What do i need more ????
>
> Thanks in advance
> René
Re: How to connect from an RCP Client via RMI to an EJB (over Http) [message #443196 is a reply to message #443166] Tue, 24 January 2006 09:58 Go to previous messageGo to next message
Eclipse User
Originally posted by: rene.huguet.besonet.ch

Hi Stefan
Thanks for your help, but after setting the securityManager i have still problems.

Here is what i have done:
1. JavaCode
System.setSecurityManager( new RMISecurityManager() );

2. VM Arguments in the richclient.product
-Djava.security.policy=rmi.policy
I'm not sure if the system reads the policy file.

3. rmi.policy file with
grant
{
permission java.security.AllPermission;
};

Now i get a access denied exception by the statement
Context ctx = new InitialContext();

Exception:
java.security.PrivilegedActionException: javax.naming.NoInitialContextException:
Cannot instantiate class: org.jboss.naming.HttpNamingContextFactory
[Root exception is java.security.AccessControlException: access denied (java.lang.RuntimePermission getClassLoader)]

What is wrong or what is missing ??
Thanks for Your help
René
Re: How to connect from an RCP Client via RMI to an EJB (over Http) [message #443197 is a reply to message #443192] Tue, 24 January 2006 10:02 Go to previous messageGo to next message
Eclipse User
Originally posted by: rene.huguet.besonet.ch

Hi Stefan
Thanks for your help, but after setting the securityManager i have still problems.

Here is what i have done:
1. JavaCode
System.setSecurityManager( new RMISecurityManager() );

2. VM Arguments in the richclient.product
-Djava.security.policy=rmi.policy
I'm not sure if the system reads the policy file.

3. rmi.policy file with
grant
{
permission java.security.AllPermission;
};

Now i get a access denied exception by the statement
Context ctx = new InitialContext();

Exception:
java.security.PrivilegedActionException: javax.naming.NoInitialContextException:
Cannot instantiate class: org.jboss.naming.HttpNamingContextFactory
[Root exception is java.security.AccessControlException: access denied (java.lang.RuntimePermission getClassLoader)]

What is wrong or what is missing ??
Thanks for Your help
René
Re: How to connect from an RCP Client via RMI to an EJB (over Http) [message #443254 is a reply to message #443197] Wed, 25 January 2006 08:58 Go to previous messageGo to next message
Stefan Langer is currently offline Stefan Langer
Messages: 236
Registered: July 2009
Senior Member
Can you debug and see if your SecurityManager is actually being called?
Where in your code are you setting it?
I guess your policy file is not being read or your Securitymanager is
not being installed. Are there any more clues in your log file?

Regards
Stefan


Rene Huguet wrote:
> Hi Stefan
> Thanks for your help, but after setting the securityManager i have still problems.
>
> Here is what i have done:
> 1. JavaCode
> System.setSecurityManager( new RMISecurityManager() );
>
> 2. VM Arguments in the richclient.product
> -Djava.security.policy=rmi.policy
> I'm not sure if the system reads the policy file.
>
> 3. rmi.policy file with
> grant
> {
> permission java.security.AllPermission;
> };
>
> Now i get a access denied exception by the statement
> Context ctx = new InitialContext();
>
> Exception:
> java.security.PrivilegedActionException: javax.naming.NoInitialContextException:
> Cannot instantiate class: org.jboss.naming.HttpNamingContextFactory
> [Root exception is java.security.AccessControlException: access denied (java.lang.RuntimePermission getClassLoader)]
>
> What is wrong or what is missing ??
> Thanks for Your help
> René
Re: How to connect from an RCP Client via RMI to an EJB (over Http) [message #443260 is a reply to message #443197] Wed, 25 January 2006 11:31 Go to previous messageGo to next message
Alex Blewitt is currently offline Alex Blewitt
Messages: 946
Registered: July 2009
Senior Member
Write a bit of test code that prints out the value of System.getProperty("java.security.policy"). My guess is that you're putting this in the wrong place and hoping that it will work :-)

At least then you know if you've configured the property correctly for your app. You'll also find that Eclipse classloaders can throw you, so anything looking for System.getResource("rmi.policy") is probably going to fail if the code that's kicking it off (e.g. the setSecurityManager()) can't read it. Load the file yourself using System.getResource("/rmi.policy") just before you do the setSecurityManager() to check it's loadable.

Do System.getSecurityManager() just after you've specified it to verify that you get the right one you're looking for.

Those are the kind of steps you should be looking for to find out where the problem is or what is missing.

Alex.
Re: How to connect from an RCP Client via RMI to an EJB (over Http) [message #443297 is a reply to message #443197] Thu, 26 January 2006 10:52 Go to previous messageGo to next message
Eclipse User
Originally posted by: rene.huguet.besonet.ch

Hi Stefan, hi Alex
I still have problems to connect with a RCP Client via RMI to a Application server.
After reading:
http://www.genady.net/forum/viewtopic.php?t=205
i decided to create my own Security Manager with all permissions.


<b>My SecurityManager</b> that allows everything (is it correct ??):
package com.prodega.ejbtest.security;
import java.security.Permission;
public class MySecurityManager extends SecurityManager {
public MySecurityManager() {
}
public void checkPermission() {
}
public void checkPermission(Permission perm) {
}
public void checkPermission(Permission perm, Object context) {
}
}


<b>My JavaCode to connect from the RCP Client:</b>
Context ctx = new InitialContext();
ctx.getEnvironment();
// Save actuel SecurityManager. The result secMan = null. Is this normal ??
SecurityManager secMan = System.getSecurityManager();
// Set MySecurityManager
System.setSecurityManager(new MySecurityManager());
Object ref = ctx.lookup("ejb/BenutzerManager");
BenutzerManagerHome home = (BenutzerManagerHome) PortableRemoteObject.narrow(ref, BenutzerManagerHome.class);
BenutzerManager bean = home.create();

<b>The Result:</b>
The ctx.lookup returns a Proxy with my ejb/BenutzerManager Object
but in PortableRemoteObject.narrow(ref, BenutzerManagerHome.class);
i get a ClassCastException.

<b>The Reason:</b>
if (narrowTo.isAssignableFrom(narrowFrom.getClass())); returns <b>false</b> (in PortableRemoteObject.narrow(...))
and
org.omg.CORBA.Object narrowObj = (org.omg.CORBA.Object) ref; throws a ClassCastException

When i start the same from a JavaClient (main method) all works fine
if (narrowTo.isAssignableFrom(narrowFrom.getClass())) returns <b>true</b>
and i get my BenutzerManagerHome object.

<b>Exception:</b>
java.lang.ClassCastException
at com.sun.corba.se.impl.javax.rmi.PortableRemoteObject.narrow( PortableRemoteObject.java:229)
at javax.rmi.PortableRemoteObject.narrow(PortableRemoteObject.j ava:137)
at com.prodega.ejbtest.EjbtestPlugin.start(EjbtestPlugin.java:8 7)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl$2 .run(BundleContextImpl.java:994)
at java.security.AccessController.doPrivileged(Native Method)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.s tartActivator(BundleContextImpl.java:988)
ClassCastException in: PortableRemoteObject.narrow(ref, BenutzerManagerHome.class);

While does it work with a JavaClient and not with a RCP Client ??
Have You experiene to connect from a RCP Client (Plug-in) via RMI to a JBoss AS ??
Do You have en example which works with a RCP Client (Plug-in) ??

Best reagrds and thanks in advance for Your help
Rene
Re: How to connect from an RCP Client via RMI to an EJB (over Http) [message #443302 is a reply to message #443297] Thu, 26 January 2006 13:07 Go to previous messageGo to next message
Alex Blewitt is currently offline Alex Blewitt
Messages: 946
Registered: July 2009
Senior Member
This occurs when the class that's being returned isn't of the same type as the class you're casting it to. Often, this is because of version mismatches in the Jars that contain the classes that are hosted on the server and on the client. It could just as easily be class mismatches with the RMI stuff as with your classes.

If you've got any pre-generated code for the classes (stubs, skeletons etc.) make sure that they're the same as are deployed to the application server. I'd also look into which Jars are being referenced in your RCP application versus which ones you're running on the command line.

Alex.
Re: How to connect from an RCP Client via RMI to an EJB (over Http) [message #443338 is a reply to message #443302] Fri, 27 January 2006 05:47 Go to previous messageGo to next message
Eclipse User
Originally posted by: rene.huguet.besonet.ch

Hi Alex

Thanks for Your help but
i still have the problem with the connection via RMI.
The JavaApplication (is better than JavaClient) is also called from inside Eclipse in debug mode.
The Program is in the same package as the RCP Client (Plug-in).
I recompiled the programs and deployed them on the server (version on Server and Client are the same).
Corba should not been involved.
I removed the statement which called a Corba method
(PortableRemoteObject.narrow(ref, BenutzerManagerHome.class);
and replaced it by:
BenutzerManagerHome home = (BenutzerManagerHome) ref; // (ref=the Proxy)
But, as expected, the result is the same.
With the JavaApplication it works fine, with the Plug-in i get the ClassCastException.

I compared the Proxys which i receive from the Server for the JavaApplication and for the RCP Client. For me they look the same.

Here an extract of the Proxy from the JavaApplication (which works):
ref= $Proxy1 (id=38 )
loaderToCache= WeakHashMap<K,V> (id=50)
m0= Method (id=54)
m1= Method (id=60)
m2= Method (id=61)
m3= Method (id=62)
m4= Method (id=63)
m5= Method (id=64)
m6= Method (id=65)
m7= Method (id=66)
m8= Method (id=67 )
nextUniqueNumber= 2 [0x2] [^B]
nextUniqueNumberLock= Object (id=68 )
pendingGenerationMarker= Object (id=69)
proxyClasses= Collections$SynchronizedMap<K,V> (id=70)
h= ClientContainer (id=73)

ejb/BenutzerManagerHome
{sun.misc.Launcher$AppClassLoader@92e78c={[org.jnp.interfaces.Naming]=java.lang.ref.WeakReference@bcb23e}, sun.rmi.server.LoaderHandler$Loader@1c4f0f8["http://RhuLaptop:8083/"]={[com.prodega.ejbtest.interfaces.BenutzerManagerHome, javax.ejb.Handle]=java.lang.ref.WeakReference@5a3923}}
public native int java.lang.Object.hashCode()
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public abstract com.prodega.ejbtest.interfaces.BenutzerManager com.prodega.ejbtest.interfaces.BenutzerManagerHome.create() throws javax.ejb.CreateException,java.rmi.RemoteException
public abstract void javax.ejb.EJBHome.remove(java.lang.Object) throws java.rmi.RemoteException,javax.ejb.RemoveException
public abstract void javax.ejb.EJBHome.remove(javax.ejb.Handle) throws java.rmi.RemoteException,javax.ejb.RemoveException
public abstract javax.ejb.EJBMetaData javax.ejb.EJBHome.getEJBMetaData() throws java.rmi.RemoteException
public abstract javax.ejb.HomeHandle javax.ejb.EJBHome.getHomeHandle() throws java.rmi.RemoteException
public abstract javax.ejb.EJBObject javax.ejb.Handle.getEJBObject() throws java.rmi.RemoteException
2
java.lang.Object@17918f0
java.lang.Object@1546dbc
{class $Proxy0=null, class $Proxy1=null}
org.jboss.proxy.ClientContainer@1d9e282
org.jboss.invocation.InvocationContext@1e0512a
org.jboss.proxy.ejb.HomeInterceptor@1f0aecc
class java.lang.Object
class java.lang.Object
interface javax.ejb.EJBHome
interface javax.ejb.EJBObject
interface javax.ejb.EJBObject
interface javax.ejb.Handle
org.jboss.proxy.SecurityInterceptor@1408a92

An extract from the h=ClientContainer EJB-METADATA
org.jboss.proxy.ejb.EJBMetaDataImpl@aa0877
interface com.prodega.ejbtest.interfaces.BenutzerManagerHome
org.jboss.proxy.ejb.handle.HomeHandleImpl@650892
null
interface com.prodega.ejbtest.interfaces.BenutzerManager


Here an extract of the Proxy from the RCP Client (which failes):
ref= $Proxy1 (id=84)
loaderToCache= WeakHashMap<K,V> (id=99)
m0= Method (id=104)
m1= Method (id=110)
m2= Method (id=111)
m3= Method (id=112)
m4= Method (id=113)
m5= Method (id=114)
m6= Method (id=115)
m7= Method (id=116)
m8= Method (id=117)
nextUniqueNumber= 2 [0x2] [^B]
nextUniqueNumberLock= Object (id=118)
pendingGenerationMarker= Object (id=119)
proxyClasses= Collections$SynchronizedMap<K,V> (id=120)
h= ClientContainer (id=123)

ejb/BenutzerManagerHome
{sun.rmi.server.LoaderHandler$Loader@135605a["http://RhuLaptop:8083/"]={[com.prodega.ejbtest.interfaces.BenutzerManagerHome, javax.ejb.Handle]=java.lang.ref.WeakReference@1da87db}, org.eclipse.core.runtime.internal.adaptor.ContextFinder@1687e7c={[org.jnp.interfaces.Naming]=java.lang.ref.WeakReference@d6c07}}
public native int java.lang.Object.hashCode()
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public abstract com.prodega.ejbtest.interfaces.BenutzerManager com.prodega.ejbtest.interfaces.BenutzerManagerHome.create() throws javax.ejb.CreateException,java.rmi.RemoteException
public abstract void javax.ejb.EJBHome.remove(java.lang.Object) throws java.rmi.RemoteException,javax.ejb.RemoveException
public abstract void javax.ejb.EJBHome.remove(javax.ejb.Handle) throws java.rmi.RemoteException,javax.ejb.RemoveException
public abstract javax.ejb.EJBMetaData javax.ejb.EJBHome.getEJBMetaData() throws java.rmi.RemoteException
public abstract javax.ejb.HomeHandle javax.ejb.EJBHome.getHomeHandle() throws java.rmi.RemoteException
public abstract javax.ejb.EJBObject javax.ejb.Handle.getEJBObject() throws java.rmi.RemoteException
2
java.lang.Object@11ff451
java.lang.Object@e0fcac
{class $Proxy0=null, class $Proxy1=null}
org.jboss.proxy.ClientContainer@1a73d30
org.jboss.invocation.InvocationContext@aefcbb
org.jboss.proxy.ejb.HomeInterceptor@528780
class java.lang.Object
class java.lang.Object
interface javax.ejb.EJBHome
interface javax.ejb.EJBObject
interface javax.ejb.EJBObject
interface javax.ejb.Handle
org.jboss.proxy.SecurityInterceptor@dfbb43

An extract from the h=ClientContainer EJB-METADATA
org.jboss.proxy.ejb.EJBMetaDataImpl@189a773
interface com.prodega.ejbtest.interfaces.BenutzerManagerHome
org.jboss.proxy.ejb.handle.HomeHandleImpl@61ec49
null
interface com.prodega.ejbtest.interfaces.BenutzerManager

What could be the problem, do You have any idea
Best Regards and thanks in advance
Rene
Re: How to connect from an RCP Client via RMI to an EJB (over Http) [message #443343 is a reply to message #443338] Fri, 27 January 2006 07:17 Go to previous messageGo to next message
Alex Blewitt is currently offline Alex Blewitt
Messages: 946
Registered: July 2009
Senior Member
It's still likely to be a classpath issue, where your BenutzerManagerHome.class is being loaded by two classloaders; the Sun RMI one and the Plugin one. The data that's being returned via the Sun RMI classloader has the same name, but has a separate instance, as the class that's referenced by your plugin. You'll probably find that if you print out .identityHashCode() of both classes, that when running as your own application you have identical references to the Class object, whereas in the RCP application you have two different references to the Class object, even if they have the same name.

You might have luck playing around with the Buddy policy, and/or doing export package of your BenutzerManager classes, but frankly I think the only way you're likely to solve this is by not using a dynamic loading of classes and doing some kind of Corba pre-compilation of stub/skeleton classes (i.e. RMI/IIOP instead of RMI/HTTP) and ensuring that the stub/skeletons are present in your plugin's classpath.

http://help.eclipse.org/help31/index.jsp?topic=/org.eclipse. platform.doc.isv/reference/misc/buddy_loading.html

That's not to say that RMI/HTTP isn't possible, but you're going to have to get down and dirty with classloader hacks to make it work.

Alex.
Re: How to connect from an RCP Client via RMI to an EJB (over Http) [message #443417 is a reply to message #443343] Sun, 29 January 2006 08:45 Go to previous messageGo to next message
Eclipse User
Originally posted by: rene.huguet.besonet.ch

Hi Alex
Thanks a lot for Your help.
You are right, it is a classLoader problem.
I have now a version which works. I'am not sure whether it is a good solution or not.
I should solve the security problem with a policy file and not with a SecurityManager which allows everything.
But i was not able to make the plug-in read the policy file.
Here the solution:

System.setProperty( "java.naming.factory.initial", "org.jboss.naming.HttpNamingContextFactory" );
System.setProperty( "java.naming.provider.url", "http://localhost:8080/invoker/JNDIFactory" );
Context ctx = new InitialContext();
ctx.getEnvironment();
System.setSecurityManager(new MySecurityManager());
Thread.currentThread().setContextClassLoader(this.getClass() .getClassLoader());
Object ref = ctx.lookup("ejb/BenutzerManager");
boolean bool = BenutzerManagerHome.class.isAssignableFrom(ref.getClass());
BenutzerManagerHome home = (BenutzerManagerHome) ref;
benutzerManagerBean = home.create();
List list = benutzerManagerBean.getBenutzerByName("");
for (Iterator iter = list.iterator(); iter.hasNext();) {
Benutzer b = (Benutzer) iter.next();
System.out.println("Benutzername = " + b.getName());
}
One week for 10 lines of code. What do You think about that ??
Best regards and thanks a lot
Rene from Berne (CH)
Re: How to connect from an RCP Client via RMI to an EJB (over Http) [message #443418 is a reply to message #443343] Sun, 29 January 2006 08:49 Go to previous message
Eclipse User
Originally posted by: rene.huguet.besonet.ch

Hi Alex
Here is a link which explains the classLoading problem:
http://user-btmurphy.jini.org/ClassLoaders_and_class_types.t xt
Rene
Previous Topic:Eclispe has 3.1 look but my RCP does not - why?
Next Topic:launch eclipse from java
Goto Forum:
  


Current Time: Thu Jul 24 21:35:31 EDT 2014

Powered by FUDForum. Page generated in 0.03092 seconds