Skip to content

Commit

Permalink
[DROOLS-1629] Allow multiple ObjectMarshallingStrategy of the same cl…
Browse files Browse the repository at this point in the history
…ass (apache#1364)
  • Loading branch information
ngs-mtech authored and mswiderski committed Jul 11, 2017
1 parent 13f0177 commit 50f6799
Show file tree
Hide file tree
Showing 5 changed files with 302 additions and 101 deletions.
Expand Up @@ -16,23 +16,25 @@

package org.drools.core.marshalling.impl;

import org.kie.api.marshalling.ObjectMarshallingStrategy;
import org.kie.api.marshalling.ObjectMarshallingStrategyAcceptor;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;

import org.kie.api.marshalling.ObjectMarshallingStrategy;
import org.kie.api.marshalling.ObjectMarshallingStrategy.Context;
import org.kie.api.marshalling.ObjectMarshallingStrategyAcceptor;

public class IdentityPlaceholderResolverStrategy
implements
ObjectMarshallingStrategy {

private Map<Integer, Object> ids;
private Map<Object, Integer> objects;

private String name = IdentityPlaceholderResolverStrategy.class.getName();
private ObjectMarshallingStrategyAcceptor acceptor;

public IdentityPlaceholderResolverStrategy(ObjectMarshallingStrategyAcceptor acceptor) {
Expand All @@ -41,10 +43,25 @@ public IdentityPlaceholderResolverStrategy(ObjectMarshallingStrategyAcceptor acc
this.objects = new IdentityHashMap<Object, Integer>();
}

public IdentityPlaceholderResolverStrategy(String name, ObjectMarshallingStrategyAcceptor acceptor) {
this( acceptor );
this.name = name;
}

public IdentityPlaceholderResolverStrategy(ObjectMarshallingStrategyAcceptor acceptor, Map<Integer, Object> ids) {
this(acceptor);
setIds(ids);
}

public IdentityPlaceholderResolverStrategy(String name, ObjectMarshallingStrategyAcceptor acceptor, Map<Integer, Object> ids){
this( acceptor, ids );
this.name = name;
}

@Override
public String getName(){
return this.name;
}

public Object read(ObjectInputStream os) throws IOException,
ClassNotFoundException {
Expand Down
Expand Up @@ -16,15 +16,33 @@

package org.drools.core.marshalling.impl;

import java.util.HashSet;
import java.util.Set;

import org.drools.core.util.StringUtils;
import org.kie.api.marshalling.ObjectMarshallingStrategy;
import org.kie.api.marshalling.ObjectMarshallingStrategyStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ObjectMarshallingStrategyStoreImpl implements ObjectMarshallingStrategyStore {
private ObjectMarshallingStrategy[] strategiesList;

private ObjectMarshallingStrategy[] strategiesList;

public ObjectMarshallingStrategyStoreImpl(ObjectMarshallingStrategy[] strategiesList) {
this.strategiesList = strategiesList;
Set<String> names = new HashSet<String>();
//Validate received set
for( ObjectMarshallingStrategy strategy : strategiesList ){
String name = strategy.getName();

if( names.contains( name ) ){
throw new RuntimeException( "Multiple ObjectMarshallingStrategies with the same name found in environment:" + name );
}else{
names.add( name );
}
}
names.clear();
}

// Old marshalling algorithm methods
Expand All @@ -51,20 +69,20 @@ public int getStrategy(Object object) {
/* (non-Javadoc)
* @see org.kie.api.marshalling.impl.ObjectMarshallingStrategyStore#getStrategyObject(java.lang.String)
*/
public ObjectMarshallingStrategy getStrategyObject(String strategyClassName) {
if( StringUtils.isEmpty(strategyClassName) ) {
public ObjectMarshallingStrategy getStrategyObject(String strategyName) {
if( StringUtils.isEmpty(strategyName) ) {
return null;
}
if (strategyClassName.startsWith("org.drools.marshalling.impl")) {
strategyClassName = strategyClassName.replaceFirst("org.drools.marshalling.impl", "org.drools.core.marshalling.impl");
if (strategyName.startsWith("org.drools.marshalling.impl")) {
strategyName = strategyName.replaceFirst("org.drools.marshalling.impl", "org.drools.core.marshalling.impl");
}
ObjectMarshallingStrategy objectMarshallingStrategy = null;

for( int i = 0; i < this.strategiesList.length; ++i ) {
if( strategiesList[i].getClass().getName().equals(strategyClassName) ) {
return strategiesList[i];
}
if( strategiesList[i].getName().equals(strategyName) ) {
return strategiesList[i];
}
}
return objectMarshallingStrategy;
throw new RuntimeException( "Unable to find PlaceholderResolverStrategy for name : " + strategyName );
}

/* (non-Javadoc)
Expand Down
Expand Up @@ -16,10 +16,18 @@

package org.drools.core.marshalling.impl;

import com.google.protobuf.ByteString;
import com.google.protobuf.ByteString.Output;
import com.google.protobuf.ExtensionRegistry;
import com.google.protobuf.Message;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;

import org.drools.core.beliefsystem.simple.BeliefSystemLogicalCallback;
import org.drools.core.common.DroolsObjectInputStream;
import org.drools.core.common.DroolsObjectOutputStream;
Expand All @@ -38,17 +46,10 @@
import org.kie.api.marshalling.ObjectMarshallingStrategy;
import org.kie.api.marshalling.ObjectMarshallingStrategy.Context;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import com.google.protobuf.ByteString;
import com.google.protobuf.ByteString.Output;
import com.google.protobuf.ExtensionRegistry;
import com.google.protobuf.Message;

public class PersisterHelper {
public static WorkingMemoryAction readWorkingMemoryAction(MarshallerReaderContext context) throws IOException,
Expand Down Expand Up @@ -239,9 +240,10 @@ public static void writeRuntimeDefinedClasses( MarshallerWriteContext context,
private static void writeStrategiesIndex(MarshallerWriteContext context,
ProtobufMessages.Header.Builder _header) throws IOException {
for( Entry<ObjectMarshallingStrategy,Integer> entry : context.usedStrategies.entrySet() ) {
Builder _strat = ProtobufMessages.Header.StrategyIndex.newBuilder()
Builder _strat = ProtobufMessages.Header.StrategyIndex.newBuilder()
.setId( entry.getValue().intValue() )
.setName( entry.getKey().getClass().getName() );
.setName( entry.getKey().getName() );

Context ctx = context.strategyContext.get( entry.getKey() );
if( ctx != null ) {
Output os = ByteString.newOutput();
Expand Down
@@ -0,0 +1,194 @@
/*
* Copyright 2017 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.drools.core.marshalling.impl;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

import org.drools.core.SessionConfiguration;
import org.drools.core.common.DefaultFactHandle;
import org.drools.core.impl.EnvironmentFactory;
import org.drools.core.impl.InternalKnowledgeBase;
import org.drools.core.impl.KnowledgeBaseFactory;
import org.junit.Assert;
import org.junit.Test;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.conf.EventProcessingOption;
import org.kie.api.marshalling.ObjectMarshallingStrategy;
import org.kie.api.marshalling.ObjectMarshallingStrategyAcceptor;
import org.kie.api.runtime.Environment;
import org.kie.api.runtime.EnvironmentName;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.runtime.rule.FactHandle;
import org.kie.internal.marshalling.MarshallerFactory;
import org.kie.internal.runtime.StatefulKnowledgeSession;

public class ObjectMarshallingStrategyStoreTest {

private class Thing{
int id;
String value;
Thing( int id, String value ){
this.id = id;
this.value = value;
}

public boolean equals( Object thing )
{
return thing!= null && thing instanceof Thing && ((Thing)thing).id == this.id;
}

public String toString(){
return "Thing:"+id+","+value;
}
}

@Test
public void testThrowErrorWhenExistMultipleMarshallingStrategiesWithSameName() throws IOException, ClassNotFoundException {

Environment env = EnvironmentFactory.newEnvironment();
final Thing entityOne = new Thing( 1, "Object 1" );
final Thing entityTwo = new Thing( 2, "Object 2" );

Collection srcItems = new ArrayList();
srcItems.add( entityOne );
srcItems.add( entityTwo );

ObjectMarshallingStrategy[] strats = new ObjectMarshallingStrategy[] {
new IdentityPlaceholderResolverStrategy( new ObjectMarshallingStrategyAcceptor() {

@Override
public boolean accept(Object object) {
return entityOne.equals(object);
}
}, Collections.singletonMap(entityOne.id, (Object) entityOne)),
new IdentityPlaceholderResolverStrategy( new ObjectMarshallingStrategyAcceptor() {

@Override
public boolean accept(Object object) {
return entityTwo.equals(object);
}
}, Collections.singletonMap(entityTwo.id, (Object) entityTwo)) };

env.set(EnvironmentName.OBJECT_MARSHALLING_STRATEGIES, strats);

KieSessionConfiguration ksc = SessionConfiguration.newInstance();

final KieBaseConfiguration kbconf = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();

kbconf.setOption(EventProcessingOption.STREAM);

InternalKnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase( kbconf );

KieSession ks = kbase.newKieSession( ksc, env);


ks.insert( entityOne );
ks.insert( entityTwo );

try{
ProtobufMarshaller marshaller = (ProtobufMarshaller) MarshallerFactory.newMarshaller(kbase, strats);
// Here ocurrs the bug that shows that NamedObjectMarshallingStrategies are required.
Assert.fail( "A runtime error must be thrown while found strategies with same name" );
}catch( RuntimeException re ){
Assert.assertTrue( re.getMessage().contains( "Multiple" ) );
}
}

@Test
public void testMultipleObjectMarshallingStrategiesOfTheSameClassWithDifferentNames() throws IOException, ClassNotFoundException {

Environment env = EnvironmentFactory.newEnvironment();
final Thing entityOne = new Thing( 1, "Object 1" );
final Thing entityTwo = new Thing( 2, "Object 2" );

Collection srcItems = new ArrayList();
srcItems.add( entityOne );
srcItems.add( entityTwo );

ObjectMarshallingStrategy[] strats = new ObjectMarshallingStrategy[] {
new IdentityPlaceholderResolverStrategy("entityOne", new ObjectMarshallingStrategyAcceptor() {

@Override
public boolean accept(Object object) {
return entityOne.equals(object);
}
}, Collections.singletonMap(entityOne.id, (Object) entityOne)),
new IdentityPlaceholderResolverStrategy("entityTwo", new ObjectMarshallingStrategyAcceptor() {

@Override
public boolean accept(Object object) {
return entityTwo.equals(object);
}
}, Collections.singletonMap(entityTwo.id, (Object) entityTwo)),
};

env.set(EnvironmentName.OBJECT_MARSHALLING_STRATEGIES, strats);

KieSessionConfiguration ksc = SessionConfiguration.newInstance();

final KieBaseConfiguration kbconf = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();

kbconf.setOption(EventProcessingOption.STREAM);

InternalKnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase( kbconf );

KieSession ks = kbase.newKieSession( ksc, env);


ks.insert( entityOne );
ks.insert( entityTwo );

ProtobufMarshaller marshaller = (ProtobufMarshaller) MarshallerFactory.newMarshaller(kbase, strats);

// Serialize object
final byte[] b1;
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
marshaller.marshall(bos, ks, System.currentTimeMillis());
b1 = bos.toByteArray();
bos.close();
}

// Deserialize object
StatefulKnowledgeSession ksession2;
{
ByteArrayInputStream bais = new ByteArrayInputStream(b1);
try{
ksession2 = marshaller.unmarshall(bais, ks.getSessionConfiguration(), ks.getEnvironment());
Collection items = ksession2.getFactHandles();
Assert.assertTrue( items.size() == 2 );
for( Object item : items ){
FactHandle factHandle = (FactHandle)item;
Assert.assertTrue( srcItems.contains( ((DefaultFactHandle)factHandle).getObject() ) );
}
}catch( RuntimeException npe ){
// Here ocurrs the bug that shows that NamedObjectMarshallingStrategies are required.
Assert.fail( "This error only happens if identity ObjectMarshallingStrategy use old name" );
}finally{
bais.close();
}


}
}

}

0 comments on commit 50f6799

Please sign in to comment.