001    /*
002      Copyright (C) 2002 Julien van Malderen, 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 org.aopalliance.intercept.ConstructorInvocation;
023    import org.aopalliance.intercept.MethodInvocation;
024    import org.apache.log4j.Logger;
025    import org.objectweb.jac.core.AspectComponent;
026    import org.objectweb.jac.core.Interaction;
027    import org.objectweb.jac.core.Wrapper;
028    import org.objectweb.jac.core.rtti.ClassItem;
029    import org.objectweb.jac.core.rtti.ClassRepository;
030    import org.objectweb.jac.core.rtti.CollectionItem;
031    import org.objectweb.jac.core.rtti.MethodItem;
032    import org.objectweb.jac.core.rtti.RttiAC;
033    
034    /**
035     * This wrapper provides a key scheme to limit fields
036     * doubles.
037     */
038    
039    public class PrimaryKeyWrapper extends Wrapper {
040        static final Logger logger = Logger.getLogger("integrity.primary");
041    
042            public PrimaryKeyWrapper(AspectComponent ac) {
043                    super(ac);
044            }
045    
046            /**
047             * This wrapping method checks if the added Object's fields match
048             * with an Object in the added collection, and throws an exception
049             * if there is one.
050             */
051            public Object checkDoubles(Interaction interaction) throws Exception {
052                    logger.debug("entering doubles-check for " + interaction.method);
053    
054                    CollectionItem coll =
055                            ((MethodItem) interaction.method).getAddedCollection();
056    
057                    String[] fieldsToComp =
058                            (String[]) coll.getAttribute(RttiAC.PRIMARY_KEY);
059    
060                    Object addedObject = interaction.args[0];
061                    logger.debug("added value: " + addedObject);
062    
063                    Collection collection = coll.getActualCollection(interaction.wrappee);
064    
065                    Object[] newFields = new Object[fieldsToComp.length];
066            ClassItem cli = ClassRepository.get().getClass(addedObject);
067                    for (int i=0; i<fieldsToComp.length; i++) {
068                            newFields[i] = 
069                    cli.getField(fieldsToComp[i])
070                                            .getThroughAccessor(addedObject);
071                    }
072    
073                    Iterator it = collection.iterator();
074                    while (it.hasNext()) {
075                            Object object = it.next();
076                            if (((fieldsToComp == null) || (fieldsToComp.length == 0))
077                                    && (object.equals(addedObject)))
078                                    throw new Exception(
079                                            "Collection "
080                                                    + coll.getName()
081                                                    + " already contains an element equals to "
082                                                    + addedObject);
083    
084                            if ((fieldsToComp.length == 0)
085                                    || (!addedObject.getClass().equals(object.getClass())))
086                                    continue;
087    
088                            int counter = 0;
089                cli = ClassRepository.get().getClass(object);
090                            for (int i=0; i<fieldsToComp.length; i++) {
091                                    Object valueToTest =
092                            cli.getField(fieldsToComp[i]).getThroughAccessor(object);
093    
094                                    if (((valueToTest == null) && (newFields[i] == null))
095                                            || ((valueToTest != null)
096                                                    && (valueToTest.equals(newFields[i]))))
097                                            counter++;
098                                    else
099                                            break;
100                            }
101                            if (counter == fieldsToComp.length) {
102                                    String fields = "";
103                                    for (int j = 0; j < fieldsToComp.length; j++) {
104                                            if (j > 0)
105                                                    fields += ", ";
106                                            fields += fieldsToComp[j];
107                                    }
108                                    throw new Exception(
109                                            "Collection "
110                                                    + coll.getName()
111                                                    + " already contains an element with fields { "
112                                                    + fields
113                                                    + " } equals to those in the added element");
114                            }
115                    }
116                    return proceed(interaction);
117            }
118    
119            public Object invoke(MethodInvocation invocation) throws Throwable {
120                    return checkDoubles((Interaction) invocation);
121            }
122    
123            public Object construct(ConstructorInvocation invocation)
124                    throws Throwable {
125                    throw new Exception("Wrapper "+this+" does not support construction interception.");
126            }
127    }