/* * 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.workbench.services.verifier.api.client.maps; import java.util.List; import java.util.TreeMap; import org.drools.workbench.services.verifier.api.client.index.keys.Key; import org.drools.workbench.services.verifier.api.client.index.keys.UUIDKey; import org.drools.workbench.services.verifier.api.client.index.keys.UpdatableKey; import org.drools.workbench.services.verifier.api.client.index.keys.Value; import org.drools.workbench.services.verifier.api.client.maps.util.HasKeys; import org.uberfire.commons.validation.PortablePreconditions; public class KeyTreeMap<T extends HasKeys> { private final TreeMap<KeyDefinition, MultiMap<Value, T, List<T>>> tree = new TreeMap<>(); protected final UUIDKeySet keys = new UUIDKeySet( this ); protected KeyChangeListener<T> keyChangeListener = new KeyChangeListener<T>() { @Override public void update( final Key oldKey, final Key newKey, final T t ) { move( oldKey, newKey, t ); } }; public KeyTreeMap( final KeyDefinition... keyIDs ) { PortablePreconditions.checkCondition( "Should not be empty", keyIDs.length != 0 ); for ( final KeyDefinition keyID : keyIDs ) { resolveMapByKeyId( keyID ); } } public void put( final T object ) { PortablePreconditions.checkNotNull( "Object can not be null", object ); final UUIDKey uuidKey = UUIDKey.getUUIDKey( object.keys() ); if ( keys.contains( uuidKey ) ) { throw new IllegalArgumentException( "UUID already already in use. You are trying to add the same object twice." ); } keys.add( uuidKey ); for ( final Key additionalKey : object.keys() ) { put( additionalKey, object ); } } private void move( final Key oldKey, final Key newKey, final T t ) { if ( newKey instanceof UpdatableKey ) { (( UpdatableKey ) newKey).addKeyChangeListener( keyChangeListener ); } if ( newKey.getKeyDefinition().isUpdatable() ) { tree.get( newKey.getKeyDefinition() ).move( oldKey.getValues(), newKey.getValues(), t ); } else { throw new IllegalArgumentException( "Key can not be updated" ); } } protected void put( final Key key, final T object ) { if ( key instanceof UpdatableKey ) { (( UpdatableKey ) key).addKeyChangeListener( keyChangeListener ); } final MultiMap<Value, T, List<T>> subMap = resolveMapByKeyId( key.getKeyDefinition() ); for ( final Value value : key.getValues() ) { subMap.put( value, object ); } } private void putAll( final KeyDefinition id, final MultiMap<Value, T, List<T>> multiMap ) { final MultiMap<Value, T, List<T>> subMap = resolveMapByKeyId( id ); for ( final Value value : multiMap.keySet() ) { subMap.addAllValues( value, multiMap.get( value ) ); } } protected MultiMap<Value, T, List<T>> resolveMapByKeyId( final KeyDefinition id ) { if ( tree.containsKey( id ) ) { return tree.get( id ); } else { final MultiMap<Value, T, List<T>> map = getMap( id ); tree.put( id, map ); return map; } } private MultiMap<Value, T, List<T>> getMap( final KeyDefinition id ) { return MultiMapFactory.make( id.isUpdatable()); } public MultiMap<Value, T, List<T>> get( final KeyDefinition keyDefinition ) { return tree.get( keyDefinition ); } public void merge( final KeyTreeMap<T> keyTreeMap ) { keys.addAll( keyTreeMap.keys ); for ( final KeyDefinition otherId : keyTreeMap.tree.keySet() ) { putAll( otherId, keyTreeMap.tree.get( otherId ) ); } } protected T remove( final UUIDKey uuidKey ) { final T item = getItemByUUID( uuidKey ); if ( item == null ) { return null; } else { final Key[] removedKeys = uuidKey.getKeys(); keys.remove( uuidKey ); if ( removedKeys == null ) { return item; } for ( final Key removedKey : removedKeys ) { if ( removeKeyForItem( removedKey, item ) ) { if ( removedKey instanceof UpdatableKey ) { (( UpdatableKey ) removedKey).removeListener( keyChangeListener ); } } } return item; } } private boolean removeKeyForItem( final Key key, final T item ) { final MultiMap<Value, T, List<T>> valueTMultiMap = tree .get( key.getKeyDefinition() ); for ( final Value value : key.getValues() ) { valueTMultiMap.get( value ).remove( item ); } // Clean up.l for ( final Value value : key.getValues() ) { if ( valueTMultiMap.get( value ).isEmpty() ) { valueTMultiMap.remove( value ); } } return true; } private T getItemByUUID( final UUIDKey uuidKey ) { if ( tree.isEmpty() ) { return null; } final MultiMap<Value, T, List<T>> valueTMultiMap = get( uuidKey.getKeyDefinition() ); if ( valueTMultiMap == null || valueTMultiMap.isEmpty() ) { return null; } final List<T> list = valueTMultiMap.get( uuidKey.getSingleValue() ); if ( list == null || list.isEmpty() ) { return null; } return list.iterator().next(); } }