001    /*
002      Copyright (C) 2002 Renaud Pawlak <renaud@aopsys.com>
003    
004      This program is free software; you can redistribute it and/or modify
005      it under the terms of the GNU Lesser General Public License as
006      published by the Free Software Foundation; either version 2 of the
007      License, or (at your option) any later version.
008    
009      This program is distributed in the hope that it will be useful,
010      but WITHOUT ANY WARRANTY; without even the implied warranty of
011      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012      GNU Lesser General Public License for more details.
013    
014      You should have received a copy of the GNU Lesser General Public License
015      along with this program; if not, write to the Free Software
016      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
017    
018    package org.objectweb.jac.aspects.integrity;
019    
020    import java.util.Collection;
021    import java.util.Iterator;
022    import java.util.List;
023    import org.aopalliance.intercept.ConstructorInvocation;
024    import org.aopalliance.intercept.MethodInvocation;
025    import org.apache.log4j.Logger;
026    import org.objectweb.jac.core.AspectComponent;
027    import org.objectweb.jac.core.Collaboration;
028    import org.objectweb.jac.core.Interaction;
029    import org.objectweb.jac.core.NameRepository;
030    import org.objectweb.jac.core.ObjectRepository;
031    import org.objectweb.jac.core.Wrapper;
032    import org.objectweb.jac.core.rtti.ClassItem;
033    import org.objectweb.jac.core.rtti.CollectionItem;
034    import org.objectweb.jac.core.rtti.FieldItem;
035    
036    /**
037     * This wrapper manages repository collections.
038     */
039    
040    public class RepositoryWrapper extends Wrapper {
041        static final Logger logger = Logger.getLogger("integrity.repository");
042            
043            public static final int ADDER = 0;
044            public static final int REMOVER = 1;
045            
046            Object repository;
047            String repositoryName;
048            CollectionItem collection;
049            FieldItem field;
050            int type = ADDER;
051    
052            public RepositoryWrapper(
053                    AspectComponent ac,
054                    String repositoryName,
055                    CollectionItem collection,
056                    FieldItem field, 
057            int type) 
058        {
059                    super(ac);
060                    this.repositoryName = repositoryName;
061                    this.collection = collection;
062                    this.field = field;
063                    this.type=type;
064            }
065    
066            /**
067             * Adds the object added to field to the repository
068             */
069            public Object addToRepository(Interaction interaction) {
070                    Object ret = doAddToRepository(interaction);
071                    if (IntegrityAC.isAddToRepositoryEnabled(collection)) {
072                            logger.debug("checking for repository on " + interaction.method);
073                            if (repository == null)
074                                    repository = NameRepository.get().getObject(repositoryName);
075                            Object toAdd = interaction.args[0];
076    
077                            if (toAdd != null
078                                    && repository != null
079                                    && !collection.getActualCollection(repository).contains(toAdd)) {
080                                    logger.debug("addToRepository(" + repositoryName + ")");
081                                    collection.addThroughAdder(repository, toAdd);
082                            }
083                    } else {
084                            logger.debug(collection + " disabled");
085                    }
086                    return ret;
087            }
088    
089            /**
090             * Disables addToRepository
091             */
092            public Object doAddToRepository(Interaction interaction) {
093            IntegrityAC.disableAddToRepository(collection);
094                    logger.debug("doAddToRepository " + collection);
095                    try {
096                            return proceed(interaction);
097                    } finally {
098                IntegrityAC.enableAddToRepository(collection);
099                    }
100            }
101    
102            public Object removeFromRepository(Interaction interaction) {
103                    logger.debug("removeFromRepository(" + repositoryName + ")");
104                    Object toRemove = interaction.args[0];
105                    FieldItem target = collection != null ? collection : field;
106                    List constraints = (List) target.getAttribute(IntegrityAC.CONSTRAINTS);
107                    if (constraints == null)
108                            return proceed(interaction);
109                    Iterator it = constraints.iterator();
110                    while (it.hasNext()) {
111                            Constraint constraint = (Constraint) it.next();
112                            Collection objects =
113                                    ObjectRepository.getObjectsWhere(
114                                            constraint.relation.getClassItem(),
115                                            constraint.relation,
116                                            toRemove);
117                            logger.debug("   " + constraint + " => " + objects);
118                            switch (constraint.constraint) {
119                                    case Constraint.DELETE_CASCADE :
120                                            break;
121                                    case Constraint.SET_NULL :
122                                            Iterator it2 = objects.iterator();
123                                            while (it2.hasNext()) {
124                                                    Object substance = it2.next();
125                                                    logger.debug(
126                                                            "      SET_NULL "
127                                                                    + substance + "." + constraint.relation);
128                                                    try {
129                                                            if (constraint.relation
130                                                                    instanceof CollectionItem) {
131                                                                    ((CollectionItem) constraint.relation)
132                                        .removeThroughRemover(
133                                            substance,
134                                            toRemove);
135                                                            } else {
136                                                                    constraint.relation.setThroughWriter(
137                                                                            substance,
138                                                                            null);
139                                                            }
140                                                    } catch (Exception e) {
141                                                            logger.error(
142                                                                    "Failed to enforce SET_NULL constraint for "
143                                    + constraint.relation + " on " + substance,e);
144                                                    }
145                                            }
146                                            break;
147                                    case Constraint.FORBIDDEN :
148                                            if (objects.size() > 0)
149                                                    throw new RuntimeException(
150                                                            "Cannot delete "
151                                                                    + toRemove + " from " + target.getLongName()
152                                                                    + " because of constraint " + constraint);
153                                            break;
154                                    default :
155                                            logger.warn(
156                                                    "Unknown constraint type " + constraint.constraint);
157                            }
158                    }
159    
160                    return proceed(interaction);
161            }
162    
163            public Object invoke(MethodInvocation invocation) throws Throwable {
164                    Interaction interaction = (Interaction) invocation;
165                    switch (type) {
166                case ADDER:
167                    return addToRepository(interaction);            
168                case REMOVER:
169                    return removeFromRepository(interaction);
170                default:
171                    throw new Exception("Unknown RepositoryWrapper type: "+type);
172                    }
173            }
174    }
175