package er.distribution.client;
import java.io.IOException;
import java.util.prefs.Preferences;
import org.apache.log4j.Logger;
import com.webobjects.eocontrol.EOClassDescription;
import com.webobjects.eodistribution.client.EODistributionChannel;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSBundle;
import er.distribution.client.exceptions.LostServerConnectionException;
import er.distribution.client.exceptions.MissingSessionException;
import er.distribution.client.exceptions.NoInstanceAvailableException;
import er.distribution.client.exceptions.RequestedApplicationNotFoundException;
import er.distribution.client.exceptions.ServerConnectionException;
import er.distribution.client.exceptions.ServerException;
import er.extensions.eof.ERXEC;
import er.extensions.logging.ERXLogger;
public abstract class ERClientApplication {
private static final Logger log = Logger.getLogger(ERClientApplication.class);
private Preferences userDefaults;
private ERDistributedObjectStore remoteObjectStore;
public ERClientApplication() {
NSBundle mainBundle = NSBundle.mainBundle(); // causes the bundle to be loaded and evaluated (will load Properties)
if (mainBundle == null) {
throw new IllegalStateException("Main bundle not found");
}
userDefaults = Preferences.userNodeForPackage( getClass() );
ERXLogger.configureLoggingWithSystemProperties();
}
protected void connectToServer() {
try {
remoteObjectStore = ERDistributedObjectStore.connectToServer();
remoteObjectStore.distributionChannel().setDelegate(this);
} catch (ServerConnectionException e) {
handleNoInstanceAvailable(e);
}
ERXEC.setDefaultParentObjectStore(remoteObjectStore);
// Fetch the class descriptions right away to avoid bugs and performance issues from doing it on demand
NSArray<EOClassDescription> classDescriptions = (NSArray<EOClassDescription>) remoteObjectStore.invokeStatelessRemoteMethod("clientSideRequestGetClassDescriptions");
registerClassDescriptions(classDescriptions);
}
/**
* Should return the name of the package where your EOEnterpriseObject classes are located
* @return the name of the package
*/
protected abstract String modelPackageName();
/**
* Note: assumes your entity names and your classes' simple-names are the same.
*
* @param classDescriptions
*/
protected void registerClassDescriptions(NSArray<EOClassDescription> classDescriptions) {
for (EOClassDescription classDescription : classDescriptions) {
String className = modelPackageName() + "." + classDescription.entityName();
Class<?> clazz;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
EOClassDescription.registerClassDescription(classDescription, clazz);
}
}
public ERDistributedObjectStore distributedObjectStore() {
return remoteObjectStore;
}
public Preferences userDefaults() {
return userDefaults;
}
/**
* EODistributionChannel.Delegate
* Gives the delegate an opportunity to handle an I/O exception which occurred while communicating with the server.
* The delegate can try to handle the exception and return a new one or null if it is able
* to deal with the exception completely. If the delegate does not want to handle the exception,
* it should return the exception passed as the ioException argument
* (which is the exception the client throws if the delegate does not implement this method or the method is not set).
*/
public IOException distributionChannelShouldThrowIOException(final EODistributionChannel channel, final IOException ioException) {
return analyzeIOException(ioException);
}
private IOException analyzeIOException(IOException ioException) {
if (ioException.getMessage().indexOf("Missing Session Error") != -1) {
return new MissingSessionException(ioException);
} else if (ioException.getMessage().indexOf("No instance available") != -1) {
return new NoInstanceAvailableException(ioException);
} else if (ioException.getMessage().indexOf("The requested application was not found on this server") != -1) {
return new RequestedApplicationNotFoundException(ioException);
} else {
return ioException;
}
}
public void handleLostServerConnectionException(LostServerConnectionException e) {
if (e instanceof MissingSessionException) {
handleMissingSession(e);
} else if (e instanceof NoInstanceAvailableException) {
handleNoInstanceAvailable(e);
} else if (e instanceof RequestedApplicationNotFoundException) {
handleNoInstanceAvailable(e);
}
}
/**
* Should show a message and exit the app.
* @param e
*/
protected abstract void handleNoInstanceAvailable(IOException e);
/**
* Session timed out or server restarted.<br>
* You could show a message like: "Your session has timed out. The application will restart." And then restart the app.
* @param e
*/
protected abstract void handleMissingSession(IOException e);
/**
* EODistributionChannel.Delegate
* Gives the delegate an opportunity to handle an exception that occurred on the server side.
* The delegate can try to handle the exception and return a new one or null if it is able
* to deal with the exception completely. If the delegate does not want to handle the exception,
* it should return the exception passed as the clientExceptionForServerException argument
* (which is the exception the client throws if the delegate does not implement this method or the method is not set).
*/
public Throwable distributionChannelShouldThrowServerException(EODistributionChannel channel,
Throwable clientExceptionForServerException, String originalServerExceptionClassName, String originalServerExceptionMessage) {
log.error(originalServerExceptionClassName + ": " + originalServerExceptionMessage, clientExceptionForServerException);
return new ServerException(clientExceptionForServerException);
}
}