org.cesecore.util.JBossUnmarshaller Maven / Gradle / Ivy
/*************************************************************************
* *
* CESeCore: CE Security Core *
* *
* This software 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 any later version. *
* *
* See terms of license at gnu.org. *
* *
*************************************************************************/
package org.cesecore.util;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedHashMap;
import org.apache.log4j.Logger;
import org.cesecore.config.CesecoreConfiguration;
/**
* Helper class for extracting objects Serialized on JBoss under J2EE.
*
* Used during upgrade from EJBCA 3.11.x to EJBCA 4.0.y.
*
* @version $Id: JBossUnmarshaller.java 23629 2016-06-08 11:53:37Z mikekushner $
*/
public final class JBossUnmarshaller {
private static final Logger LOG = Logger.getLogger(JBossUnmarshaller.class);
private static final String JBOSS_MARSHALL_CLASS = "org.jboss.invocation.MarshalledValue";
private static boolean lookForJbossMarshaller = true;
private JBossUnmarshaller() {
}
/**
* Helper method for extracting objects Serialized on JBoss under J2EE.
*
* The methods uses the fact that org.jboss.invocation.MarshalledValue is also a Serializable object and extracts the real object from the
* MarshalledValue if this is passed as a parameter. Otherwise the object is returned in it's current form.
*
* @param
* Class that we are trying to extract.
* @param t
* Class that we are trying to extract.
* @param object
* An object implementing java.lang.Serializable interface
* @return The unmarshalled or original object of type T or null if object is neither type T or jboss marshalled value
* @throws ClassCastException if the object is JBOSS marshalled, but not of type t
*/
@SuppressWarnings("unchecked")
public static T extractObject(final Class t, final Serializable object) throws ClassCastException {
T ret = null;
final String className = object.getClass().getName();
if (JBOSS_MARSHALL_CLASS.equals(className)) {
try {
Method m = object.getClass().getMethod("get", new Class[0]);
ret = (T) m.invoke(object, new Object[0]);
} catch (SecurityException e) {
LOG.error("", e);
} catch (NoSuchMethodException e) {
LOG.error("", e);
} catch (IllegalArgumentException e) {
LOG.error("", e);
} catch (IllegalAccessException e) {
LOG.error("", e);
} catch (InvocationTargetException e) {
LOG.error("", e);
}
} else {
ret = (T) object;
}
return ret;
}
/**
* Helper method for extracting hashMaps Serialized on JBoss under J2EE.
*
* The method tries to extract a LinkedHashMap that was serialized. A complicating factor is that previously we used to use HashMap
* instead of LinkedhashMap, therefore we need this helper method to fall through to extracting a HashMap instead of a LinkedHashMap.
*
* @param
* Class that we are trying to extract.
* @param t
* Class that we are trying to extract.
* @param object
* An object implementing java.lang.Serializable interface
* @return The unmarshalled or original object of type T or null if object is neither type T or jboss marshalled value
* @throws ClassCastException if the object is JBOSS marshalled, but not of type t
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static LinkedHashMap extractLinkedHashMap(final Serializable object) {
LinkedHashMap ret = null;
// When the wrong class is given it can either return null, or throw an exception
try {
ret = JBossUnmarshaller.extractObject(LinkedHashMap.class, object);
if (ret != null) {
return ret;
}
} catch (ClassCastException e) {
// NOPMD: pass through to the end line
}
// If this is an old record, before we switched to LinkedHashMap, we have to try that, we should get a ClassCastException or null from above...
return new LinkedHashMap(JBossUnmarshaller.extractObject(HashMap.class, object));
}
/**
* During upgrade from EJBCA 3.11.x to EJBCA 4.0.x on a 100% up-time cluster, we will have old EJB 2.1 CMP serialization on JBoss installations
* together with new EJB 3.0 JPA pure Java serialization.
*
* Until all nodes has been upgraded, we have to keep storing things as before, to not break the old installations.
* This is what the flag keepJbossSerializationIfUsed is used for.
*
* @param object
* if the object that will be stored as a BLOB
* @return either the pure object or a JBoss serialized version of the Object
*/
public static Serializable serializeObject(final Serializable object) {
Serializable ret = object;
if (lookForJbossMarshaller && CesecoreConfiguration.isKeepJbossSerializationIfUsed()) {
try {
// Do "ret = new org.jboss.invocation.MarshalledValue(object)" with inflection, since we can't know
// if we are running on a JBoss AS or not.
ret = (Serializable) Class.forName(JBOSS_MARSHALL_CLASS).getConstructor(Object.class).newInstance(object);
} catch (ClassNotFoundException e1) {
LOG.debug(JBOSS_MARSHALL_CLASS + " does not exist. Assuming that this is a non-JBoss installation.");
lookForJbossMarshaller = false; // Can only go from true to false, so there is no need for synchronization
} catch (Exception e) {
LOG.error("Unable to store as JBoss MarshalledValue.", e);
}
}
return ret;
}
}