/*
* ALMA - Atacama Large Millimiter Array
* (c) European Southern Observatory, 2005
* Copyright by ESO (in the framework of the ALMA collaboration),
* All rights reserved
*
* This library 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 library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
package alma.acsexmplErrorComponent.ErrorComponentImpl;
import org.omg.CORBA.NO_IMPLEMENT;
import alma.ACSErr.Completion;
import alma.ACSErrTypeCommon.ACSErrTypeCommonEx;
import alma.ACSErrTypeCommon.GenericErrorEx;
import alma.ACSErrTypeCommon.wrappers.AcsJACSErrTypeCommonEx;
import alma.ACSErrTypeCommon.wrappers.AcsJGenericErrorEx;
import alma.ACSErrTypeCommon.wrappers.GenericErrorAcsJCompletion;
import alma.ACSErrTypeOK.wrappers.ACSErrOKAcsJCompletion;
import alma.acs.component.ComponentImplBase;
import alma.acs.exceptions.AcsJCompletion;
import alma.acs.exceptions.AcsJException;
import alma.acsexmplErrorComponent.ErrorComponentOperations;
/**
* Implementation of the <code>ErrorComponent</code> interface,
* which should demonstrate proper use of the ACS error system in Java.
* <p>
* Note on logging: unlike in the C++ implementation of this component, here we do not log the invocation
* of every method, because the Java container does this automatically.
* In general the component should only trace the invocations itself if it needs to add custom data to the log.
* @author hsommer
*/
public class ErrorComponentImpl extends ComponentImplBase implements ErrorComponentOperations {
public void displayMessage() {
m_logger.info("ErrorComponent");
}
/**
* An intentionally bad method that throws an exception (<code>GenericErrorEx</code>)
* if <code>depth</code> > 0. This exception has causing exception if depth > 1.
* All exceptions get added to the <code>ErrorTrace</code> list which will transport them over CORBA.
* <p>
* Note that the thrown CORBA exception <code>GenericErrorEx</code> only acts as a vehicle for the embedded <code>ErrorTrace</code> linked list
* which contains the real data of the exception(s).
* @see alma.acsexmplErrorComponent.ErrorComponentOperations#badMethod(short)
*/
@Override
public void badMethod(short depth) throws GenericErrorEx {
try {
// our internal method uses the convenient "AcsJ-" JDK-style variant of GenericErrorEx
internalBadMethod(depth);
} catch (AcsJGenericErrorEx e) {
// when leaving the Java component boundary, we must convert the JDK-style-exception to its plain CORBA/ACS-style peer.
throw e.toGenericErrorEx();
} catch (Throwable thr) {
throw new AcsJGenericErrorEx("Got unexpected exception", thr).toGenericErrorEx();
}
}
/**
* An intentionally bad method that throws a CORBA::BAD_PARAM system exception
* to show how to handle CORBA System Exceptions
* @see alma.acsexmplErrorComponent.ErrorComponentOperations#corbaSystemException()
*/
@Override
public void corbaSystemException() throws org.omg.CORBA.SystemException {
throw new org.omg.CORBA.BAD_PARAM("Test throwing a CORBA Exception");
}
/**
* This method throws a <code>GenericErrorEx</code> exception if the completion
* returned from {@link #internalCompletionMethod(int)} has an associated exception.
* This will be the case if the <code>depth</code> parameter is > 0.
* @see alma.acsexmplErrorComponent.ErrorComponentOperations#exceptionFromCompletion(short)
*/
@Override
public void exceptionFromCompletion(short depth) throws GenericErrorEx {
try {
if (depth == 1) {
// this case is ugly if we really want to fulfill the contract and throw a single exception (i.e. error trace of length one).
// It seems that for an example component we should work without a 'depth' parameter, and rather have two different methods instead of this highly powerful one method.
AcsJCompletion completion = internalCompletionMethod(depth);
// here we cannot wrap the contained exception, because then the total error trace would be of depth == 2.
// Therefore we must check for the correct exception type, and use that exception directly.
if (completion.getAcsJException() instanceof AcsJGenericErrorEx) {
AcsJGenericErrorEx knownEx = (AcsJGenericErrorEx) completion.getAcsJException();
throw knownEx.toGenericErrorEx();
}
else {
// this should never happen
throw new AcsJGenericErrorEx("Unexpected component implementation bug. AcsJGenericErrorEx was expected in Completion object.").toGenericErrorEx();
}
}
else {
// with depth != 1 we can construct a completion with (depth-1) exceptions, and wrap those with a new exception if they exist
AcsJCompletion completion = internalCompletionMethod(depth - 1);
// completion should have an error unless depth was 0
if (completion.isError()) {
AcsJException acsjEx = completion.getAcsJException();
throw (new AcsJGenericErrorEx(acsjEx)).toGenericErrorEx();
}
}
} catch (GenericErrorEx ex) {
throw ex; // that's our checked exception
} catch (Throwable thr) {
// that's an unchecked exception which we must wrap
throw new AcsJGenericErrorEx("Got unexpected exception", thr).toGenericErrorEx();
}
}
@Override
public void typeException(short depth) throws ACSErrTypeCommonEx { //, GenericErrorEx {
try {
internalBadMethod(depth);
} catch (AcsJACSErrTypeCommonEx ex) {
// here we made use of the inheritance hierarchy in the AcsJ-style exceptions,
// and caught the flying AcsJGenericErrorEx through its base type AcsJACSErrTypeCommonEx
throw ex.toACSErrTypeCommonEx();
} catch (Throwable thr) {
throw new AcsJGenericErrorEx("Got unexpected exception", thr).toACSErrTypeCommonEx();
}
}
/**
*
* @see alma.acsexmplErrorComponent.ErrorComponentOperations#completionFromException(short)
*/
@Override
public Completion completionFromException(short depth) {
// this completion will be built from a chain of exceptions if depth > 0
AcsJCompletion completion = internalCompletionMethod(depth);
return completion.toCorbaCompletion();
}
/**
*
* @see alma.acsexmplErrorComponent.ErrorComponentOperations#completionFromCompletion(short)
*/
@Override
public Completion completionFromCompletion(short depth) {
AcsJCompletion completion = null;
if (depth <= 1) {
completion = internalCompletionMethod(depth);
return completion.toCorbaCompletion();
}
else {
completion = internalCompletionMethod(depth - 1);
// here we show how to wrap the error from a given completion with a new completion
AcsJCompletion newCompletion = new GenericErrorAcsJCompletion(completion);
return newCompletion.toCorbaCompletion();
}
}
/**
* Forwards to {@link #completionFromException(short)} because in Java we can't create objects on the stack, so
* there is no distinction to be made.
*
* @see alma.acsexmplErrorComponent.ErrorComponentOperations#completionOnStack(short)
*/
@Override
public Completion completionOnStack(short depth) {
return completionFromException(depth);
}
/**
* this method returns a Completion as an out parameter.
*
* @see alma.acsexmplErrorComponent.ErrorComponentOperations#outCompletion(alma.ACSErr.CompletionHolder)
*/
public void outCompletion(alma.ACSErr.CompletionHolder comp) {
comp.value = (new ACSErrOKAcsJCompletion()).toCorbaCompletion();
}
@Override
public void generateSIGFPE(short way) {
throw new NO_IMPLEMENT();
}
@Override
public void generateSIGSEGV(short way) {
throw new NO_IMPLEMENT();
}
///////////////////////////////////////////////////////////////////////
/**
* Method that calls itself recursively to construct an AcsJGenericErrorEx exception
* with causing exceptions of the same type.
* <p>
* This behavior is meant to mimic a number of calls down into the implementation classes of a real-world component,
* even though there we would typically deal with different methods calling one another,
* instead of the same method calling itself recursively.
* @param depth the number of chained exceptions thrown in the end. May be zero, meaning that no exception will be thrown.
* @throws AcsJGenericErrorEx, which is the JDK-style peer of {@link GenericErrorEx}.
*/
private void internalBadMethod(int depth) throws AcsJGenericErrorEx {
if (depth < 1) {
return;
}
if (depth == 1) {
throw new AcsJGenericErrorEx("This exception is the original cause.");
}
try {
// recursion
internalBadMethod(depth - 1);
}
catch (AcsJGenericErrorEx ex) {
// we use the causing exception to build up the JDK-style chain of exceptions.
// That chain will later be converted into an ACS-style ErrorTrace.
throw new AcsJGenericErrorEx("This exception was caused by another exception...", ex);
}
}
/**
* Creates a completion, optionally based on a chain of exceptions.
* @param depth The number of chained exceptions attached to the completion, which may be zero.
* @return
*/
private AcsJCompletion internalCompletionMethod(int depth) {
if (depth <= 0) {
// a completion type that has no exception associated
return new ACSErrOKAcsJCompletion();
}
else if (depth == 1) {
return new GenericErrorAcsJCompletion();
}
else {
try {
internalBadMethod(depth - 1);
} catch (AcsJGenericErrorEx ex) {
// a completion which takes associated exceptions (and wraps them with a GenericError exception)
return new GenericErrorAcsJCompletion(ex);
}
}
// this should never happen, given that for depth>0 we always get an exception from internalBadMethod.
// We throw an unchecked exception to give a real-world example for such a case,
// because at the Java impl / CORBA boundary it is often not good enough to just consider checked exceptions.
throw new RuntimeException("Program error: was never supposed to get here!");
}
@Override
public void sleepingCmd(short nbSeconds) {
try {
Thread.sleep(nbSeconds * 1000);
}
catch (InterruptedException ex) {
m_logger.warning("Woke up early from an InterruptedException");
}
}
}