Ticket #2375: change-deleted-element.patch

File change-deleted-element.patch, 15.9 KB (added by mira, 15 years ago)
  • src/main/java/org/sophie2/main/app/commons/element/ElementView.java

    ### Eclipse Workspace Patch 1.0
    #P org.sophie2.main.app.commons
     
    7676        } 
    7777 
    7878        private RwProp<TimePos> localTime() { 
    79                 return getBean().makeValueProp("localTime", TimePos.class, TimePos.INTRO_START); 
     79                return getBean().makeValueProp("localTime", TimePos.class, TimePos.MAIN_START); 
    8080        } 
    8181 
    8282        /** 
  • src/main/java/org/sophie2/base/model/resources/r4/changes/AutoAction.java

    #P org.sophie2.base.model.resources.r4
     
    77import java.util.concurrent.ConcurrentHashMap; 
    88import java.util.concurrent.ConcurrentMap; 
    99 
     10import org.sophie2.base.commons.util.ImmList; 
    1011import org.sophie2.base.commons.util.NaiveImmList; 
    1112import org.sophie2.base.model.resources.r4.ResourceRefR4; 
    1213import org.sophie2.base.model.resources.r4.access.DelegatingAccess; 
     
    7980                ResourceRefR4 changeScope = ((DelegatingAccess) access).location; 
    8081                 
    8182                 
    82                 final Class<? extends AutoAction> autoActionClass = this.getClass(); 
     83                Class<? extends AutoAction> autoActionClass = this.getClass(); 
     84                ImmList<Object> values = getConstructorArgs(this); 
    8385                 
    84                 NaiveImmList<Object> values = NaiveImmList.<Object>getEmpty(); 
     86                access.registerChange(new ModelChange(changeScope,  
     87                                access.getAccessOptions().getUser(), 
     88                                access.getAccessOptions().getViewId(), 
     89                                this.description, this.significant, autoActionClass, 
     90                                values)); 
     91        } 
     92         
     93        /** 
     94         * Gets the constructor arguments for the resurrection of a given  
     95         * {@link AutoAction} object.  
     96         *  
     97         * @param autoAction 
     98         *                      The {@link AutoAction} that will be resurrected.   
     99         * @return 
     100         *                      {@link ImmList} with constructor arguments. 
     101         */ 
     102        public static ImmList<Object> getConstructorArgs(AutoAction autoAction) { 
     103                Class<? extends AutoAction> autoActionClass = autoAction.getClass(); 
    85104 
     105                NaiveImmList<Object> values = NaiveImmList.<Object>getEmpty(); 
    86106                try { 
    87107                        List<Field> fields = AutoAction.Registry.getAccessibleDeclaredFileds( 
    88108                                        autoActionClass); 
    89109                        for (Field field : fields) { 
    90                                 Object value = field.get(this); 
     110                                Object value = field.get(autoAction); 
    91111                                if (value != null && !ProUtil.isImmutable(value.getClass())) { 
    92112                                        value = null; 
    93113                                } 
     
    99119                        throw new RuntimeException(e); 
    100120                } 
    101121                 
    102                 access.registerChange(new ModelChange(changeScope,  
    103                                 access.getAccessOptions().getUser(), 
    104                                 access.getAccessOptions().getViewId(), 
    105                                 this.description, this.significant, autoActionClass, 
    106                                 values)); 
     122                return values; 
    107123        } 
    108          
     124 
    109125        /** 
    110126         * @author tsachev 
    111127         * 
     
    134150                                } 
    135151                                List<Field> fieldsList = Collections.<Field>unmodifiableList( 
    136152                                                Arrays.asList(declaredFields)); 
    137                                 REGISTRY.putIfAbsent(actionClass,  
    138                                                 fieldsList); 
     153                                REGISTRY.putIfAbsent(actionClass, fieldsList); 
    139154                        } 
    140155                        return REGISTRY.get(actionClass); 
    141156                } 
  • src/main/java/org/sophie2/server/core/persistence/db/DBChangeContext.java

    #P org.sophie2.server.core
     
    120120                 *                      The key to visit,. 
    121121                 */ 
    122122                public KeyValueVisitor(ResourceDAO dao, Key<T> key) { 
    123                         super(dao, key.getValueClass()); 
     123                        super(dao, key.getValueClass(), getId()); 
    124124 
    125125                        this.key = key; 
    126126                } 
  • src/main/java/org/sophie2/server/core/persistence/db/ReadKeyVisitor.java

     
    2424public final class ReadKeyVisitor<T> extends 
    2525                RootAndChildrenVisitor<T> { 
    2626        private final Key<T> key; 
    27         private final RevisionId revisionId; 
    28  
    2927        /** 
    3028         * Constructs the visitor. 
    3129         *  
     
    3836         */ 
    3937        public ReadKeyVisitor(ResourceDAO dao, 
    4038                        Key<T> key, RevisionId revisionId) { 
    41                 super(dao, key.getValueClass()); 
     39                super(dao, key.getValueClass(), revisionId); 
    4240                this.key = key; 
    43                 this.revisionId = revisionId; 
    4441        } 
    4542 
    4643        @Override 
     
    4946                // All other types of keys: 
    5047                try { 
    5148                        String dbValue =  
    52                                 getDao().findValue(localResPath, keyPath, this.revisionId.getId()); 
     49                                getDao().findValue(localResPath, keyPath, getRevisionId().getId()); 
    5350 
    5451                        setResult(this.key.getValueClass().cast(ResourceServiceDBImpl.stringToValue(dbValue))); 
    5552                } catch (IOException e) { 
  • src/main/java/org/sophie2/server/core/persistence/db/RootAndChildrenVisitor.java

     
    77import org.sophie2.base.model.resources.r4.immutables.NaiveSubEntryNames; 
    88import org.sophie2.base.model.resources.r4.immutables.SubEntryNames; 
    99import org.sophie2.base.model.resources.r4.keys.ChildrenKey; 
     10import org.sophie2.base.model.resources.r4.model.RevisionId; 
    1011 
    1112/** 
    1213 * A key visitor that can handle retrieving of the root and child key values. 
     
    2223        private final Class<T> keyValueClass; 
    2324         
    2425        private T result = null; 
     26        private final RevisionId revisionId; 
    2527         
    2628        /** 
    2729         * Constructs the visitor. 
     
    3032         *                      A {@link ResourceDAO} to retrieve data from. 
    3133         * @param keyValueClass 
    3234         *                      The value class of the key to visit, used for casting. 
     35         * @param revisionId  
     36         *                      The revision to visit keys in.  
    3337         */ 
    34         public RootAndChildrenVisitor(ResourceDAO dao, Class<T> keyValueClass) { 
     38        public RootAndChildrenVisitor(ResourceDAO dao, Class<T> keyValueClass, RevisionId revisionId) { 
    3539                this.dao = dao; 
    3640                this.keyValueClass = keyValueClass; 
     41                this.revisionId = revisionId; 
    3742        } 
    3843         
    3944        @Override 
    4045        protected void handleChildrenKey(String localResPath, String keyPath, 
    4146                        Object value) throws ResponseException { 
    4247                // If the key passed is the children key: 
    43                 List<String> childResources = this.dao.findChildResources(localResPath); 
     48                List<String> childResources = this.dao.findChildResources(localResPath, this.revisionId); 
    4449                 
    4550                SubEntryNames names = NaiveSubEntryNames.create((Collection<String>) childResources); 
    4651                this.result = this.keyValueClass.cast(names); 
     
    9196        } 
    9297         
    9398        /** 
     99         * Gets the revision id.  
     100         *  
     101         * @return 
     102         *                      The id of the revision in which the keys are going to be visited.  
     103         */ 
     104        public RevisionId getRevisionId() { 
     105                return this.revisionId; 
     106        } 
     107         
     108        /** 
    94109         * Getter of the result of the visit action. 
    95110         * To be called after executing the {@link #visitKey(String, String, Object)} 
    96111         * method. 
  • src/main/resources/distrib/data/queries.properties

     
    2525select \ 
    2626        r.resource_name \ 
    2727from \ 
    28          t_resources r \ 
    29 join mv_resource_paths rp on r.parent_id = rp.resource_id \ 
    30 where \ 
    31         rp.resource_path = ? 
    32          
     28        t_resources r \ 
     29        join mv_resource_paths rp on r.parent_id = rp.resource_id \ 
     30where   (rp.resource_path = ?) \ 
     31        and \ 
     32            exists ( \ 
     33            select kv.key_value \ 
     34            from t_key_values kv \ 
     35                join t_key_value_changes kvc on kv.key_value_change_id = kvc.id \ 
     36                join t_keys k on kvc.key_id = k.id \ 
     37                join mv_resource_paths rp on kvc.resource_id = rp.resource_id \ 
     38                cross join (select rev.id from t_revisions rev where rev.revision_id = ?) rev \ 
     39            where \ 
     40                (kvc.key_id = ?) \ 
     41                and kvc.resource_id = r.id \ 
     42                and (set_revision_id <= rev.id) \ 
     43                and ((change_revision_id is null) or (change_revision_id > rev.id )) \ 
     44            )  
     45             
    3346select_resource_key_names=\ 
    3447select \ 
    3548    k.key_path \ 
  • src/test/java/org/sophie2/server/core/facade/MergeChangesTest.java

     
     1package org.sophie2.server.core.facade; 
     2 
     3import java.util.List; 
     4 
     5import javax.swing.SwingUtilities; 
     6 
     7import org.junit.Before; 
     8import org.junit.Test; 
     9import org.sophie2.base.commons.util.ImmColor; 
     10import org.sophie2.base.commons.util.ImmList; 
     11import org.sophie2.base.commons.util.NaiveImmList; 
     12import org.sophie2.base.commons.util.position.ImmSize; 
     13import org.sophie2.base.connectivity.BaseConnectivityModule; 
     14import org.sophie2.base.connectivity.facade.HistoryEntry; 
     15import org.sophie2.base.model.book.BaseModelBookModule; 
     16import org.sophie2.base.model.book.BookH; 
     17import org.sophie2.base.model.book.interfaces.StyledElement; 
     18import org.sophie2.base.model.resources.r4.BaseModelResourcesR4Module; 
     19import org.sophie2.base.model.resources.r4.ResourceRefR4; 
     20import org.sophie2.base.model.resources.r4.access.ResourceAccess; 
     21import org.sophie2.base.model.resources.r4.changes.AutoAction; 
     22import org.sophie2.base.model.resources.r4.changes.ModelChange; 
     23import org.sophie2.base.model.resources.r4.changes.ResourceChanger; 
     24import org.sophie2.base.model.resources.r4.keys.RootKey; 
     25import org.sophie2.base.model.resources.r4.keys.UndefinedKey; 
     26import org.sophie2.base.model.resources.r4.model.ResourceModel; 
     27import org.sophie2.base.model.resources.r4.model.RevisionId; 
     28import org.sophie2.base.persistence.BasePersistenceModule; 
     29import org.sophie2.core.modularity.FakeModuleRegistry; 
     30import org.sophie2.server.core.persistence.access.DBResourceAccess; 
     31import org.sophie2.server.core.persistence.db.DBModelTest; 
     32import org.sophie2.server.core.persistence.db.ResourceServiceDBImpl; 
     33import org.sophie2.server.core.persistence.db.ServerResourceHelperDBImpl; 
     34 
     35/** 
     36 * Tests The merge method of the facade in different cases.  
     37 *  
     38 * @author mira, meddle 
     39 */ 
     40public class MergeChangesTest extends DBModelTest { 
     41 
     42        private static final String SERVER_URL = "http://localhost:8003"; 
     43 
     44        private ServerFacade facade = null; 
     45        private DBResourceAccess access; 
     46 
     47        @Override 
     48        @Before 
     49        protected void setUp() throws Exception { 
     50                super.setUp(); 
     51                SwingUtilities.invokeAndWait(new Runnable() { 
     52 
     53                        @SuppressWarnings("unchecked") 
     54                        public void run() { 
     55                                FakeModuleRegistry.start(BasePersistenceModule.class,  
     56                                                BaseModelResourcesR4Module.class,  
     57                                                BaseModelBookModule.class, 
     58                                                BaseConnectivityModule.class); 
     59                        } 
     60                }); 
     61 
     62                ServerResourceHelperDBImpl.fillDatabase(getDao()); 
     63 
     64                ResourceServiceDBImpl service = new ResourceServiceDBImpl( 
     65                                getDao(), SERVER_URL); 
     66 
     67                ServerSession session = new ServerSession(); 
     68 
     69                this.facade = new ServerFacade(service, session); 
     70                this.access = DBResourceAccess.findWebAccess(service, 
     71                                ResourceRefR4.make(SERVER_URL + "/" +  
     72                                                ServerResourceHelperDBImpl.MAIN_DIR_NAME), 
     73                                                SERVER_URL); 
     74        } 
     75 
     76        private BookH createInitialBook() { 
     77                final ResourceRefR4 bookRef = ResourceRefR4.generateRandomSub("Book"); 
     78 
     79                new AutoAction("Make book", true) { 
     80 
     81                        @Override 
     82                        public void performAuto() { 
     83                                getChanger().makeResource(bookRef); 
     84                                ResourceModel model = BookH.createInitialModel( 
     85                                                "Test book", "Test Page", new ImmSize(400f, 250f)); 
     86 
     87                                ResourceChanger bookCh = getChanger().getSub(bookRef); 
     88                                bookCh.setRaw(UndefinedKey.make(RootKey.ROOT_ID_PARTS), model); 
     89                        } 
     90 
     91                }.register(this.access); 
     92                ResourceAccess bookAccess = this.access.open(bookRef, null); 
     93                return new BookH(bookAccess); 
     94        } 
     95 
     96        /** 
     97         * Tests the invalidation changes to deleted elements. 
     98         *  
     99         * @throws Exception 
     100         */ 
     101        @Test 
     102        public void testMergeChanges() throws Exception { 
     103                BookH bookH = createInitialBook(); 
     104                ResourceRefR4 mergingResource = bookH.getRef(); 
     105                RevisionId lastSyncId = new RevisionId(getDao().findRevisionNotAfter( 
     106                                RevisionId.FUTURE.getId())); 
     107                ResourceRefR4 pageRef = bookH.getPages().get(0); 
     108                ModelChange change = createChange(pageRef); 
     109                RevisionId currentChangeId = RevisionId.generateAfter(lastSyncId); 
     110                HistoryEntry histEntry = new HistoryEntry(change, currentChangeId); 
     111                List<HistoryEntry> changes = this.facade.merge( 
     112                                mergingResource, lastSyncId, NaiveImmList.create(histEntry)); 
     113 
     114                assertSame(1, changes.size()); 
     115                lastSyncId = changes.get(0).getRevisionId(); 
     116 
     117                ModelChange deleteChange = createDeleteChange(pageRef); 
     118                currentChangeId = RevisionId.generateAfter(lastSyncId); 
     119                histEntry = new HistoryEntry(deleteChange, currentChangeId); 
     120                changes = this.facade.merge(mergingResource, lastSyncId, 
     121                                NaiveImmList.create(histEntry)); 
     122 
     123                assertSame(1, changes.size()); 
     124                lastSyncId = changes.get(0).getRevisionId(); 
     125 
     126                currentChangeId = RevisionId.generateAfter(lastSyncId); 
     127                histEntry = new HistoryEntry(change, currentChangeId); 
     128                changes = this.facade.merge(mergingResource, lastSyncId, 
     129                                NaiveImmList.create(histEntry)); 
     130                //this change should be invalid... 
     131                assertSame(0, changes.size()); 
     132        } 
     133 
     134        private ModelChange createChange(ResourceRefR4 pageRef) { 
     135                String description = "Change page border"; 
     136                AutoAction autoAction = new AutoAction(description, true) { 
     137                        @Override 
     138                        public void performAuto() { 
     139                                getChanger().setRaw(StyledElement.KEY_BORDER__COLOR, ImmColor.BLUE);  
     140                        } 
     141                }; 
     142                ImmList<Object> fields = AutoAction.getConstructorArgs(autoAction); 
     143                ModelChange res = new ModelChange(pageRef, null, null,  
     144                                description, true, autoAction.getClass(), fields); 
     145                return res; 
     146        } 
     147 
     148        private ModelChange createDeleteChange(final ResourceRefR4 pageRef) { 
     149                String description = "Delete page"; 
     150                AutoAction autoAction = new AutoAction(description, true) { 
     151                        @Override 
     152                        public void performAuto() { 
     153                                getChanger().removeResource(pageRef); 
     154                        } 
     155                }; 
     156                ImmList<Object> fields = AutoAction.getConstructorArgs(autoAction); 
     157                ModelChange res = new ModelChange(ResourceRefR4.CURRENT_REF, null, null,  
     158                                description, true, autoAction.getClass(), fields); 
     159                return res; 
     160        } 
     161 
     162} 
  • src/main/java/org/sophie2/server/core/persistence/db/ResourceDAO.java

     
    1414import org.sophie2.base.model.resources.r4.keys.Key; 
    1515import org.sophie2.base.model.resources.r4.keys.RootKey; 
    1616import org.sophie2.base.model.resources.r4.keys.UndefinedKey; 
     17import org.sophie2.base.model.resources.r4.model.RevisionId; 
    1718import org.sophie2.base.model.resources.r4.resources.ResourceR4; 
    1819import org.sophie2.server.core.persistence.db.jdbc.JdbcTemplate; 
    1920import org.sophie2.server.core.persistence.db.jdbc.ResultSetMapper; 
     
    414415         *  
    415416         * @param resourcePath 
    416417         *                      The path of the resource which children will be retrieved. 
     418         * @param revisionId  
    417419         * @return 
    418420         *                      The names of the child resources in the DB. 
    419421         */ 
    420         public List<String> findChildResources(String resourcePath) { 
     422        public List<String> findChildResources(String resourcePath, RevisionId revisionId) { 
    421423                String query = SqlQueries.get(SELECT_CHILD_RESOURCE_NAMES); 
    422424 
    423425                return this.jdbcTemplate.queryForList(query, new StringRowMapper(), 
    424                                 resourcePath); 
     426                                resourcePath, revisionId.getId(), 1); 
    425427        } 
    426428 
    427429        /**