/* * Copyright 2004-2009 the original author or authors. * * 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.compass.core.cascade; import java.lang.reflect.Array; import java.util.Collection; import org.compass.core.CompassException; import org.compass.core.config.CompassConfigurable; import org.compass.core.config.CompassEnvironment; import org.compass.core.config.CompassSettings; import org.compass.core.config.ConfigurationException; import org.compass.core.mapping.Cascade; import org.compass.core.mapping.CascadeMapping; import org.compass.core.mapping.CompassMapping; import org.compass.core.mapping.ResourceMapping; import org.compass.core.spi.AliasedObject; import org.compass.core.spi.DirtyOperationContext; import org.compass.core.spi.InternalCompassSession; /** * Cascading manager supports perfoming cascade opeations on Objects. * * @author kimchy */ public class CascadingManager implements CompassConfigurable { private InternalCompassSession session; private CompassMapping mapping; private CompassCascadeFilter cascadeFilter; public CascadingManager(InternalCompassSession session) { this.session = session; this.mapping = session.getMapping(); configure(session.getCompass().getSettings()); } public void configure(CompassSettings settings) throws CompassException { String filterName = settings.getSetting(CompassEnvironment.Cascade.FILTER_TYPE); if (filterName != null) { try { Class filterClass = settings.getSettingAsClass(CompassEnvironment.Cascade.FILTER_TYPE, CompassCascadeFilter.class); cascadeFilter = (CompassCascadeFilter) filterClass.newInstance(); } catch (Exception e) { throw new ConfigurationException("Unable to create cascade filter of class " + filterName, e); } } } public boolean cascade(Object root, Cascade cascade, DirtyOperationContext context) throws CompassException { if (cascadingDisabled()) return false; if (root instanceof AliasedObject) { return cascade(((AliasedObject) root).getAlias(), root, cascade, context); } return cascade(root.getClass(), root, cascade, context); } public boolean cascade(String alias, Object root, Cascade cascade, DirtyOperationContext context) throws CompassException { if (cascadingDisabled()) return false; ResourceMapping resourceMapping = mapping.getMappingByAlias(alias); return resourceMapping != null && cascade(resourceMapping, root, cascade, context); } public boolean cascade(Class clazz, Object root, Cascade cascade, DirtyOperationContext context) throws CompassException { if (cascadingDisabled()) return false; ResourceMapping resourceMapping = mapping.getMappingByClass(clazz); return resourceMapping != null && cascade(resourceMapping, root, cascade, context); } public boolean shouldCascade(Object root, Cascade cascade) throws CompassException { if (cascadingDisabled()) return false; if (root instanceof AliasedObject) { return shouldCascade(((AliasedObject) root).getAlias(), root, cascade); } return shouldCascade(root.getClass(), root, cascade); } public boolean shouldCascade(String alias, Object root, Cascade cascade) throws CompassException { if (cascadingDisabled()) return false; ResourceMapping resourceMapping = mapping.getMappingByAlias(alias); return resourceMapping != null && shouldCascade(resourceMapping, root, cascade); } public boolean shouldCascade(Class clazz, Object root, Cascade cascade) throws CompassException { if (cascadingDisabled()) return false; ResourceMapping resourceMapping = mapping.getMappingByClass(clazz); return resourceMapping != null && shouldCascade(resourceMapping, root, cascade); } private boolean shouldCascade(ResourceMapping resourceMapping, Object root, Cascade cascade) throws CompassException { if (cascadingDisabled()) return false; CascadeMapping[] cascadeMappings = resourceMapping.getCascadeMappings(); if (cascadeMappings == null) { return false; } for (CascadeMapping cascadeMapping : cascadeMappings) { if (cascadeMapping.shouldCascade(cascade)) { return true; } } return false; } private boolean cascade(ResourceMapping resourceMapping, Object root, Cascade cascade, DirtyOperationContext context) throws CompassException { if (cascadingDisabled()) return false; CascadeMapping[] cascadeMappings = resourceMapping.getCascadeMappings(); if (cascadeMappings == null) { return false; } boolean retVal = false; for (CascadeMapping cascadeMapping : cascadeMappings) { if (cascadeMapping.shouldCascade(cascade)) { retVal = true; Object value = cascadeMapping.getCascadeValue(root); if (value == null) { continue; } if (value instanceof Object[]) { int length = Array.getLength(value); for (int j = 0; j < length; j++) { cascadeOperation(cascade, Array.get(value, j), context); } } else if (value instanceof Collection) { for (Object o : ((Collection) value)) { cascadeOperation(cascade, o, context); } } else { cascadeOperation(cascade, value, context); } } } return retVal; } private void cascadeOperation(Cascade cascade, Object value, DirtyOperationContext context) { // TODO what happens if there are several aliases for value if (value == null) { return; } if (cascade == Cascade.DELETE) { if (cascadeFilter != null && cascadeFilter.shouldFilterDelete(value)) { return; } session.delete(value, context); } else if (cascade == Cascade.CREATE) { if (cascadeFilter != null && cascadeFilter.shouldFilterCreate(value)) { return; } session.create(value, context); } else if (cascade == Cascade.SAVE) { if (cascadeFilter != null && cascadeFilter.shouldFilterSave(value)) { return; } session.save(value, context); } else { throw new IllegalArgumentException("Failed to perform cascading unknown type [" + cascade + "]"); } } private boolean cascadingDisabled() { return session.getSettings().getSettingAsBoolean(CompassEnvironment.Cascade.DISABLE, false); } }