bug5032: using the JoinedClassloader in the DataMiningService for function de-serialization

This commit is contained in:
Axel Uhl
2019-12-12 16:04:07 +01:00
parent 21e249cef5
commit 53a4c77dc6
8 changed files with 50 additions and 56 deletions
@@ -21,7 +21,6 @@ import org.osgi.util.tracker.ServiceTracker;
import com.sap.sailing.server.interfaces.RacingEventService;
import com.sap.sse.common.settings.SerializableSettings;
import com.sap.sse.datamining.DataMiningServer;
import com.sap.sse.datamining.ModifiableDataMiningServer;
import com.sap.sse.datamining.Query;
import com.sap.sse.datamining.StatisticQueryDefinition;
import com.sap.sse.datamining.components.AggregationProcessorDefinition;
@@ -33,7 +32,6 @@ import com.sap.sse.datamining.functions.Function;
import com.sap.sse.datamining.impl.components.DataRetrieverLevel;
import com.sap.sse.datamining.impl.components.management.ReducedDimensions;
import com.sap.sse.datamining.impl.data.QueryResultImpl;
import com.sap.sse.datamining.shared.DataMiningQuerySerializer;
import com.sap.sse.datamining.shared.DataMiningSession;
import com.sap.sse.datamining.shared.GroupKey;
import com.sap.sse.datamining.shared.SerializationDummy;
@@ -59,19 +57,15 @@ public class DataMiningServiceImpl extends ProxiedRemoteServiceServlet implement
private static final long serialVersionUID = -7951930891674894528L;
private final BundleContext context;
private final ServiceTracker<DataMiningServer, DataMiningServer> dataMiningServerTracker;
private final ServiceTracker<SecurityService, SecurityService> securityServiceTracker;
private final StoredDataMiningQueryPersister storedDataMiningQueryPersistor;
private final DataMiningDTOFactory dtoFactory;
public DataMiningServiceImpl() {
context = Activator.getDefault();
dataMiningServerTracker = createAndOpenDataMiningServerTracker(context);
securityServiceTracker = ServiceTrackerFactory.createAndOpen(context, SecurityService.class);
storedDataMiningQueryPersistor = new StoredDataMiningQueryPersisterImpl(getSecurityService(),
dataMiningServerTracker);
dtoFactory = new DataMiningDTOFactory();
@@ -439,7 +433,6 @@ public class DataMiningServiceImpl extends ProxiedRemoteServiceServlet implement
@Override
public ModifiableStatisticQueryDefinitionDTO getDeserializedQuery(String serializedQuery) {
return (ModifiableStatisticQueryDefinitionDTO) DataMiningQuerySerializer.fromBase64String(serializedQuery,
((ModifiableDataMiningServer) dataMiningServerTracker.getService()).getJoinedClassLoader());
return (ModifiableStatisticQueryDefinitionDTO) dataMiningServerTracker.getService().fromBase64String(serializedQuery);
}
}
@@ -13,7 +13,6 @@ import com.sap.sailing.server.impl.preferences.model.StoredDataMiningQueryPrefer
import com.sap.sailing.server.impl.preferences.model.StoredDataMiningQueryPreferences;
import com.sap.sse.common.Util;
import com.sap.sse.datamining.DataMiningServer;
import com.sap.sse.datamining.ModifiableDataMiningServer;
import com.sap.sse.datamining.shared.DataMiningQuerySerializer;
import com.sap.sse.datamining.shared.dto.StatisticQueryDefinitionDTO;
import com.sap.sse.datamining.shared.dto.StoredDataMiningQueryDTO;
@@ -114,8 +113,7 @@ public class StoredDataMiningQueryPersisterImpl implements StoredDataMiningQuery
/** Converts a {@link StoredDataMiningQueryPreference} to a {@link StoredDataMiningQueryDTO}. */
private StoredDataMiningQueryDTO transform(StoredDataMiningQueryPreference pref) {
StatisticQueryDefinitionDTO query = DataMiningQuerySerializer.fromBase64String(pref.getSerializedQuery(),
((ModifiableDataMiningServer) dataMiningServerTracker.getService()).getJoinedClassLoader());
StatisticQueryDefinitionDTO query = dataMiningServerTracker.getService().fromBase64String(pref.getSerializedQuery());
return new StoredDataMiningQueryDTOImpl(pref.getName(), pref.getId(), query);
}
@@ -13,5 +13,6 @@ Export-Package: com.sap.sse.datamining.shared,
com.sap.sse.datamining.shared.util
Bundle-ActivationPolicy: lazy
Require-Bundle: com.sap.sse.datamining.annotations,
com.sap.sse.common
com.sap.sse.common,
com.sap.sse.shared.android
Automatic-Module-Name: com.sap.sse.datamining.shared
@@ -1,11 +1,8 @@
package com.sap.sse.datamining.shared;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.util.logging.Logger;
import com.sap.sse.common.Base64Utils;
@@ -30,37 +27,4 @@ public final class DataMiningQuerySerializer {
}
return "";
}
/** @return the {@link StatisticQueryDefinitionDTO} from a base 64 string deserialized with java serialization */
public static StatisticQueryDefinitionDTO fromBase64String(final String string, ClassLoader joinedClassLoader) {
byte[] bytes;
try {
bytes = Base64Utils.fromBase64(string);
} catch (IllegalArgumentException e) {
return null;
}
try (ByteArrayInputStream stream = new ByteArrayInputStream(bytes)) {
ObjectInputStream in = new ObjectInputStream(stream) {
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if (joinedClassLoader != null) {
try {
return joinedClassLoader.loadClass(desc.getName());
} catch (ClassNotFoundException e) {
return super.resolveClass(desc);
}
}
return super.resolveClass(desc);
}
};
Object o = in.readObject();
if (o instanceof StatisticQueryDefinitionDTO) {
return (StatisticQueryDefinitionDTO) o;
}
} catch (IOException | ClassNotFoundException e) {
LOG.severe("Could not load query: " + e.getMessage());
}
return null;
}
}
@@ -4,17 +4,15 @@ import org.junit.Assert;
import org.junit.Test;
import com.sap.sailing.datamining.SailingPredefinedQueries;
import com.sap.sse.datamining.impl.DataMiningServerImpl;
import com.sap.sse.datamining.shared.DataMiningQuerySerializer;
import com.sap.sse.datamining.shared.dto.StatisticQueryDefinitionDTO;
public class DataMiningQuerySerializerTest {
@Test
public void testSerializationAndDeserialization() {
// test null
testSerializationAndDeserialization(null);
// test all predefined queries
for (StatisticQueryDefinitionDTO query : new SailingPredefinedQueries().getQueries().values()) {
testSerializationAndDeserialization(query);
@@ -23,7 +21,10 @@ public class DataMiningQuerySerializerTest {
private void testSerializationAndDeserialization(final StatisticQueryDefinitionDTO dto) {
String base64 = DataMiningQuerySerializer.toBase64String(dto);
StatisticQueryDefinitionDTO deserialized = DataMiningQuerySerializer.fromBase64String(base64, null);
StatisticQueryDefinitionDTO deserialized = new DataMiningServerImpl(
/* executorService */ null, /* functionRegistry */ null, /* dataSourceProviderRegistry */ null,
/* dataRetrieverChainDefinitionRegistry */ null, /* aggregationProcessorDefinitionRegistry */ null,
/* queryDefinitionRegistry */ null).fromBase64String(base64);
Assert.assertEquals(dto, deserialized);
}
}
@@ -26,6 +26,7 @@ import com.sap.sse.datamining.shared.impl.dto.DataRetrieverChainDefinitionDTO;
import com.sap.sse.datamining.shared.impl.dto.FunctionDTO;
import com.sap.sse.datamining.shared.impl.dto.ModifiableStatisticQueryDefinitionDTO;
import com.sap.sse.i18n.ResourceBundleStringMessages;
import com.sap.sse.util.JoinedClassLoader;
public interface DataMiningServer {
@@ -52,6 +53,8 @@ public interface DataMiningServer {
<DataSourceType, ResultType> Query<ResultType> createQuery(StatisticQueryDefinition<DataSourceType, ?, ?, ResultType> queryDefinition);
<ResultType> QueryResult<ResultType> runNewQueryAndAbortPreviousQueries(DataMiningSession session, Query<ResultType> query);
int getNumberOfRunningQueries();
JoinedClassLoader getJoinedClassLoader();
StatisticQueryDefinitionDTO fromBase64String(String string);
//-----------------------------------------------------------------------------------------------------------------
// Component Accessors as default methods
@@ -128,5 +131,4 @@ public interface DataMiningServer {
default ModifiableStatisticQueryDefinitionDTO getPredefinedQueryDefinitionDTO(PredefinedQueryIdentifier identifier) {
return getQueryDefinitionDTOProvider().get(identifier);
}
}
@@ -9,13 +9,11 @@ import com.sap.sse.datamining.components.management.QueryDefinitionDTORegistry;
import com.sap.sse.datamining.shared.dto.StatisticQueryDefinitionDTO;
import com.sap.sse.datamining.shared.impl.PredefinedQueryIdentifier;
import com.sap.sse.i18n.ResourceBundleStringMessages;
import com.sap.sse.util.JoinedClassLoader;
public interface ModifiableDataMiningServer extends DataMiningServer {
void addDataMiningBundleClassLoader(ClassLoader classLoader);
void removeDataMiningBundleClassLoader(ClassLoader classLoader);
JoinedClassLoader getJoinedClassLoader();
void addStringMessages(ResourceBundleStringMessages stringMessages);
void removeStringMessages(ResourceBundleStringMessages stringMessages);
@@ -1,5 +1,8 @@
package com.sap.sse.datamining.impl;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
@@ -12,7 +15,10 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sse.common.Base64Utils;
import com.sap.sse.common.settings.SerializableSettings;
import com.sap.sse.datamining.DataSourceProvider;
import com.sap.sse.datamining.ModifiableDataMiningServer;
@@ -50,8 +56,10 @@ import com.sap.sse.datamining.shared.impl.dto.FunctionDTO;
import com.sap.sse.i18n.ResourceBundleStringMessages;
import com.sap.sse.i18n.impl.CompoundResourceBundleStringMessages;
import com.sap.sse.util.JoinedClassLoader;
import com.sap.sse.util.ObjectInputStreamResolvingAgainstCache;
public class DataMiningServerImpl implements ModifiableDataMiningServer {
private static final Logger logger = Logger.getLogger(DataMiningServerImpl.class.getName());
private static final long MEMORY_CHECK_PERIOD = 5;
private static final TimeUnit MEMORY_CHECK_PERIOD_UNIT = TimeUnit.SECONDS;
@@ -90,7 +98,6 @@ public class DataMiningServerImpl implements ModifiableDataMiningServer {
this.dataSourceProviderRegistry = dataSourceProviderRegistry;
this.dataRetrieverChainDefinitionRegistry = dataRetrieverChainDefinitionRegistry;
this.aggregationProcessorDefinitionRegistry = aggregationProcessorDefinitionRegistry;
this.queryDefinitionRegistry = queryDefinitionRegistry;
}
@@ -143,6 +150,36 @@ public class DataMiningServerImpl implements ModifiableDataMiningServer {
return new JoinedClassLoader(dataMiningClassLoaders);
}
/**
* @return the {@link StatisticQueryDefinitionDTO} from a base 64 string deserialized with java serialization,
* considering the {@link #getJoinedClassLoader() joined class loader} that offers all classes of all
* bundles that currently provide data mining components to this server
*/
@Override
public StatisticQueryDefinitionDTO fromBase64String(final String string) {
byte[] bytes;
try {
bytes = Base64Utils.fromBase64(string);
} catch (IllegalArgumentException e) {
return null;
}
final ClassLoader oldThreadContextClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(getJoinedClassLoader());
try (final ObjectInputStream in = new ObjectInputStreamResolvingAgainstCache<Object>(
new ByteArrayInputStream(bytes), /* dummy "cache" */ new Object(), /* resolve listener */ null) {}) {
Object o = in.readObject();
if (o instanceof StatisticQueryDefinitionDTO) {
return (StatisticQueryDefinitionDTO) o;
}
} catch (IOException | ClassNotFoundException e) {
logger.log(Level.SEVERE, "Could not load query", e);
} finally {
Thread.currentThread().setContextClassLoader(oldThreadContextClassLoader);
}
return null;
}
@Override
public void addDataMiningBundleClassLoader(ClassLoader classLoader) {
dataMiningClassLoaders.add(classLoader);