Clinet runs in JVM A , Server Runs in JVM B.
There are all EJB Call from client to server.
Now any of the 2 objects I expect in Client side.
Array of LoanDocument
or
BusinessServicesException
public interface LoanViewerServicesLocal extends EJBLocalObject {
public LoanDocument[] getDocByLoanNumber (String loanNum)
throws BusinessServicesException;
public interface LoanViewerServices extends EJBObject {
public LoanDocument[] getDocByLoanNumber (String loanNum)
throws RemoteException,BusinessServicesException;
Now BusinessServicesException extends CommonException; CommonException extends ProjectException; ProjectException extends Exception.
I specified a serialVersionUID value of 1L in all my 3 exception class (both client and server side ) to avoid de-serialization issue in Client side.
Otherwise I will get
java.io.InvalidClassException: com.abc.common.ProjectException; local class incompatible: stream classdesc serialVersionUID = 354159461886461208, local class serialVersionUID = -5937350397277039691
Hence mention 1L in all 3 classes (serialVersionUID =1L) resolve the issue.
Now LoanDocument objects extends CommonDocumentObject but none of then having serialVersionUID or implements Serializable interface.
But when we get successful LoanDocument[] in client side, I am not getting any serialVersionUID related exception due to deserialization?
I tested several times, But I always get same serialVersionUID for LoanDocument and in CommonDocumentObject.
I use below mention code in Server and Clinet and I get always same serialVersionUID in both sides.
But always different in case of BusinessServicesException.
Class loanDocClass = LoanDocument.getClass();
long uid = ObjectStreamClass.lookup(loanDocClass).getSerialVersionUID();
when we get successful LoanDocument[] in client side, I am not getting any serialVersionUID related exception due to deserialization?
Because you haven't done any changes to that class between deployment to the server and deployment to the client. In the other cases, you had.
Related
I have JAX-RS web app, and i want to log amount of time from getting request to response. It was easy in the Spring Boot with servlet filters. But the filter in my app does not work properly:
#Provider
public class RequestLogFilter implements ContainerRequestFilter, ContainerResponseFilter {
private long requestStartTime;
#Override
public void filter(ContainerRequestContext requestContext) {
requestStartTime = System.currentTimeMillis();
}
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
long requestFinishTime = System.currentTimeMillis();
System.out.println(requestFinishTime - requestStartTime);
}
}
It works fine in the first method, where current timestamps writes in the requestStartTime. But, seems like the second method has own copy of requestStartTime variable, because it the second method it always equals to zero. So i cant calculate the difference between variables. What can i do instead to log request processing time?
Since you are implementing both ContainerRequestFilter and ContainerResponseFilter in the same class, it seems that 2 different instances are created, therefore the variable requestStartTime is different between the 2 instances.
This problem was reported on the Eclipse Jersey project and considered a bug, which has been solved, see https://github.com/eclipse-ee4j/jersey/issues/3796.
Here the whole discussion: https://github.com/eclipse-ee4j/jaxrs-api/issues/605.
The argument was that this behavior does not conform the JAX-RS specification (Section 4.1):
By default a single instance of each provider class is instantiated
for each JAX-RS application
But Quarkus uses RESTEasy, so I guess that it doesn't contain that fix.
Anyway, even if a single instance was created (for example using the annotation #Singleton) you still shouldn't use an instance variable to keep the start time since concurrent requests would override it (thanks to #areus for pointing that out).
Instead you could save the start time on the properties of ContainerRequestContext on ContainerRequestFilter.filter() and then get it and use it on ContainerResponseFilter.filter():
#Provider
public class RequestLogFilter implements ContainerRequestFilter, ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext) {
long requestStartTime = System.nanoTime();
requestContext.setProperty("requestStartTime", requestStartTime);
}
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) {
long requestStartTime = (long) requestContext.getProperty("requestStartTime");
long requestFinishTime = System.nanoTime();
long duration = requestFinishTime - requestStartTime;
System.out.println("duration: " + TimeUnit.NANOSECONDS.toMillis(duration) + " ms");
}
}
Actually, something similar is built-in to Quarkus thanks to the MicroProfile Metrics API:
Add the SmallRye Metrics extension (quarkus-smallrye-metrics) to your pom.xml
This should be enabled by default, but feel free to explicitly enable the RestEasy/JAX-RS metrics to be registered by adding the following to application.properties:
quarkus.smallrye-metrics.extensions.enabled=true
The metrics (# invocations, time spent in each) will be added to the /metrics endpoint. The metrics will show up once you invoke the endpoint.
To cross the language boundary in Java side the class to be serialized needs to implement the DataSerializable interface; and in order to let the deserializer in c# know what class it is , we need to register a classID. Following the example, I write my class in Java like this:
public class Stuff implements DataSerializable{
static { // note that classID (7) must match C#
Instantiator.register(new Instantiator(Stuff.class,(byte)0x07) {
#Override
public DataSerializable newInstance() {
return new Stuff();
}
});
}
private Stuff(){}
public boolean equals(Object obj) {...}
public int hashCode() {...}
public void toData(DataOutput dataOutput) throws IOException {...}
public void fromData(DataInput dataInput) throws IOException, ClassNotFoundException { ...}
}
It looks OK but when I run it I get this exception:
[warning 2012/03/30 15:06:00.239 JST tid=0x1] Error registering
instantiator on pool:
com.gemstone.gemfire.cache.client.ServerOperationException: : While
performing a remote registerInstantiators at
com.gemstone.gemfire.cache.client.internal.AbstractOp.processAck(AbstractOp.java:247)
at
com.gemstone.gemfire.cache.client.internal.RegisterInstantiatorsOp$RegisterInstantiatorsOpImpl.processResponse(RegisterInstantiatorsOp.java:76)
at
com.gemstone.gemfire.cache.client.internal.AbstractOp.attemptReadResponse(AbstractOp.java:163)
at
com.gemstone.gemfire.cache.client.internal.AbstractOp.attempt(AbstractOp.java:363)
at
com.gemstone.gemfire.cache.client.internal.ConnectionImpl.execute(ConnectionImpl.java:229)
at
com.gemstone.gemfire.cache.client.internal.pooling.PooledConnection.execute(PooledConnection.java:321)
at
com.gemstone.gemfire.cache.client.internal.OpExecutorImpl.executeWithPossibleReAuthentication(OpExecutorImpl.java:646)
at
com.gemstone.gemfire.cache.client.internal.OpExecutorImpl.execute(OpExecutorImpl.java:108)
at
com.gemstone.gemfire.cache.client.internal.PoolImpl.execute(PoolImpl.java:624)
at
com.gemstone.gemfire.cache.client.internal.RegisterInstantiatorsOp.execute(RegisterInstantiatorsOp.java:39)
at
com.gemstone.gemfire.internal.cache.PoolManagerImpl.allPoolsRegisterInstantiator(PoolManagerImpl.java:216)
at
com.gemstone.gemfire.internal.InternalInstantiator.sendRegistrationMessageToServers(InternalInstantiator.java:188)
at
com.gemstone.gemfire.internal.InternalInstantiator._register(InternalInstantiator.java:143)
at
com.gemstone.gemfire.internal.InternalInstantiator.register(InternalInstantiator.java:71)
at com.gemstone.gemfire.Instantiator.register(Instantiator.java:168)
at Stuff.(Stuff.java)
Caused by: java.lang.ClassNotFoundException: Stuff$1
I could not figure out why, is there anyone who has experience can help? Thanks in advance!
In most configurations GemFire servers need to deserialize objects in order to index them, run queries and call listeners. So when you register instantiator the class will be registered on all machines in the Distributed System. Hence, the class itself must be available for loading everywhere in the cluster.
As exception stack trace says the error happens on a remote node.
Check if you have the class Stuff on all machines participating in the cluster. At least on cache servers.
I'm working on a project using Java RMI.
This is the class causing problem:
public class FSFile implements Serializable
{
public static final int READ = 0;
public static final int WRITE = 1;
private int flag;
private String filename;
private transient BufferedWriter writer;
private transient BufferedReader reader;
...
private void writeObject(ObjectOutputStream stream) throws IOException
{
stream.defaultWriteObject();
stream.writeObject(writer);
stream.writeObject(reader);
}
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
{
stream.defaultReadObject();
writer = (BufferedWriter) stream.readObject();
reader = (BufferedReader) stream.readObject();
}
}
Basically, I use RMI to send that FSFile object to another process locally (for now) and here's the error I get:
java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException;
java.io.BufferedReader
To be more precise, there's one class named FileService which use a function fetch() from a FileServer to get a FSFile in return. There is nothing special in the fetch() function, it just creates a FSFile and returns it. All communications between those classes are made via RMI.
How come I have an error like this ?
You can't serialize readers and writers. It makes no sense. It's like trying to send a telephone over a telephone line. If you want to send a file, send the file.
And your code just calls writeObject on these objects as though they were Serializable. They aren't. Otherwise you could have made them non-transient and omitted the custom readObject and writeObject methods altogether. Just re-coding what the system would have done anyway doesn't change anything. It certainly doesn't make classes Serializable that aren't.
If you don't want to re-implement file/stream sending via RMI you could look into RMIIO, it handles such things in concise and effective way.
I have a WCF application , with multiple WSDL webservices, hosted in IIS7 on Windows Server 2008 64Bit.
The application requires a singleton to be assigned with some configuration values once, when the first webservice method is invoked (no matter what is invoked first).
Edit: The backend of the system requires the use of this singleton approach.
I get the configuration assigned once, but the values become null again....
Here is the code (simplified):
public class SingletonSettings
{
private static readonly SingletonSettings _s;
public SingletonSettings Instance { get {return _s;} }
public object SomeValue { get; set; }
}
public abstract class AbstractWebservice
{
static AbstractWebservice()
{
WebserviceGlobalInitializer.Initialize();
}
}
//Just a webservice
public class Webservice1 : AbstractWebservice, ISomeServiceConctract1
{
public void DoStuff1();
}
//Just a webservice
public class Webservice2 : AbstractWebservice, ISomeServiceConctract2
{
public void DoStuff2();
}
internal class WebserviceGlobalInitializer
{
private static readonly object Lock = new object();
private static bool Initialized = false;
public static void Initialize()
{
lock (Lock)
{
if (!Initialized)
{
InitStuff();
Initialized = true;
}
}
}
private static void InitStuff()
{
string s = SingletonSettings.Instance.SomeValue = "just a ref";
}
}
WebserviceGlobalInitializer.InitStuff() gets invoked only once. Still SingletonSettings.SomeValue becomes null.....
The issue occurs randomly.
I have tried
1) Invoking WebserviceGlobalInitializer.Initialize() from a normal constructor in the base class.
2) Commenting out: Initialized = true; in hope that the settings would then be initialized every time (causing massive overhead, so it would not be a long term solution anyway)
Still the value becomes null.
Any ideas?
With process recycling, all state that is not in session state or application state will disappear into the black hole. This, eye-openingly, includes the static variables, one of which is the singleton instance.
My gut feeling is that the InstanceContextMode of singleton has been implemented as a variable in the ASP.NET Application state. To check this, I will be doing some reflectoring today and will update my answer.
UPDATE
NO IT DOESN'T!!! With process recycling, even if you set the WCF Instancing mode to Single, you lose all state you had with your singleton instance (e.g. counter, whatever) with process recycling.
After a few more days of searching i found the source of the problem. Aliostad's answer gave me a hint.
My webservice uses behavior configurations. One with authentication and one without.
The authentication/session handling is implemented in an IDispatchMessageInspector which is invoked before the webservice is loaded.
The problem occurred when an application that uses my webservice was online when the application pool was recycled. Then application would then a request to a webservice using the authenticated behavior.
The IDispatchMessageInspector implemention would then try to load the settings, but they have not yet been initialized from the static constructor in the webservice....
Thank you for the answers...
You can use the WCF runtime infrastructure to take care of this for you. Try adding the following attribute to the WebService class:
[ServiceBehavior(
ConcurrencyMode = ConcurrencyMode.Multiple,
InstanceContextMode = InstanceContextMode.Single)]
The class below (my implementation of UserDetailsService) gets tied to the session and the session gets serialized (in google apps engine).
I watched a Spring 3 presentation recently that said that beans, such as userDao, shown below, are loaded by a proxy which doesn't serialize the bean, but stores only the name and re-obtains the reference on deserialization.
But with the below code I'm getting a NotSerializableException: com.prepayproxy.dataaccesslayer.GAEUserDao
#Service("springUserDetailsService")
public class SpringUserDetailsService implements UserDetailsService, Serializable {
#Resource(name="userDao")
private IUserDao userDao;
//...
}
You have 2 options:
Mark the dao as transient so it does not serialize.
Serialize the dao yourself.
Java provides a means to serialize non-serializable objects. You will need to implement
private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;
The Serializable interface includes a writeup of these methods. Here is a link to the docs (java 1.6) Serializable