/* * Copyright 2016 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.ruleunit; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map; import java.util.Optional; import org.drools.core.WorkingMemoryEntryPoint; import org.drools.core.datasources.InternalDataSource; import org.drools.core.impl.StatefulKnowledgeSessionImpl; import org.drools.core.rule.EntryPointId; import org.kie.api.runtime.rule.DataSource; import org.kie.api.runtime.rule.RuleUnit; import static org.drools.core.util.ClassUtils.getter2property; public class RuleUnitDescr { private final Class<? extends RuleUnit> ruleUnitClass; private final Map<String, String> datasources = new HashMap<>(); private final Map<String, Class<?>> datasourceTypes = new HashMap<>(); private final Map<String, Method> varAccessors = new HashMap<>(); public RuleUnitDescr( Class<? extends RuleUnit> ruleUnitClass ) { this.ruleUnitClass = ruleUnitClass; indexUnitVars(); } public Class<? extends RuleUnit> getRuleUnitClass() { return ruleUnitClass; } public String getRuleUnitName() { return ruleUnitClass.getName(); } private String getEntryPointName(String name) { return getRuleUnitName() + "." + name; } public Optional<EntryPointId> getEntryPointId( String name ) { return Optional.ofNullable( datasources.get( name ) ).map( ds -> new EntryPointId( getEntryPointName(name) ) ); } public Optional<Class<?>> getDatasourceType( String name ) { return Optional.ofNullable( datasourceTypes.get( name ) ); } public Optional<Class<?>> getVarType( String name ) { return Optional.ofNullable( varAccessors.get( name ) ).map( m -> m.getReturnType() ); } public boolean hasVar( String name ) { return varAccessors.get( name ) != null; } public void bindDataSources( StatefulKnowledgeSessionImpl wm, RuleUnit ruleUnit ) { datasources.forEach( (name, accessor) -> bindDataSource( wm, ruleUnit, name, accessor ) ); } public void unbindDataSources( StatefulKnowledgeSessionImpl wm, RuleUnit ruleUnit ) { datasources.forEach( (name, accessor) -> findDataSource( ruleUnit, accessor ).ifPresent( ds -> ds.unbind( ruleUnit ) ) ); // TODO review // datasources.values().forEach( accessor -> findDataSource( ruleUnit, accessor ).filter(AbstractReactiveDataSource.class::isInstance) // .map( AbstractReactiveDataSource.class::cast ) // .ifPresent( AbstractReactiveDataSource::unbind ) ); } private void bindDataSource( StatefulKnowledgeSessionImpl wm, RuleUnit ruleUnit, String name, String accessor ) { Optional<InternalDataSource> datasource = findDataSource( ruleUnit, accessor ); Optional<WorkingMemoryEntryPoint> entrypoint = datasource.flatMap( ds -> propagateInserts( wm, ruleUnit, name, ds ) ); // TODO review // datasource.filter(AbstractReactiveDataSource.class::isInstance) // .map( AbstractReactiveDataSource.class::cast ) // .ifPresent( ds -> ds.bind( entrypoint.orElse( null ), ruleUnit ) ); } public Object getValue(RuleUnit ruleUnit, String identifier) { Method m = varAccessors.get(identifier); if (m != null) { try { return m.invoke( ruleUnit ); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException( e ); } } return null; } private Optional<InternalDataSource> findDataSource( RuleUnit ruleUnit, String accessor ) { try { Object value = ruleUnit.getClass().getMethod( accessor ).invoke( ruleUnit ); return value instanceof InternalDataSource ? Optional.of( (InternalDataSource) value ) : Optional.empty(); } catch (Exception e) { throw new RuntimeException( e ); } } private Optional<WorkingMemoryEntryPoint> propagateInserts( StatefulKnowledgeSessionImpl wm, RuleUnit ruleUnit, String dataSourceName, InternalDataSource dataSource ) { Optional<WorkingMemoryEntryPoint> entryPoint = Optional.ofNullable( wm.getEntryPoint( getEntryPointName( dataSourceName ) ) ); entryPoint.ifPresent( ep -> dataSource.bind( ruleUnit, ep ) ); return entryPoint; } private void indexUnitVars() { for (Method m : ruleUnitClass.getMethods()) { if ( m.getDeclaringClass() != RuleUnit.class && m.getParameterCount() == 0 ) { String id = getter2property(m.getName()); if (id != null && !id.equals( "class" )) { if (DataSource.class.isAssignableFrom( m.getReturnType() )) { datasources.put( id, m.getName() ); Type returnType = m.getGenericReturnType(); Class<?> sourceType = returnType instanceof ParameterizedType ? (Class<?>) ( (ParameterizedType) returnType ).getActualTypeArguments()[0] : Object.class; datasourceTypes.put( id, sourceType ); } varAccessors.put( id, m ); } } } } }