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
76 76 } 77 77 78 78 private RwProp<TimePos> localTime() { 79 return getBean().makeValueProp("localTime", TimePos.class, TimePos. INTRO_START);79 return getBean().makeValueProp("localTime", TimePos.class, TimePos.MAIN_START); 80 80 } 81 81 82 82 /** -
src/main/java/org/sophie2/base/model/resources/r4/changes/AutoAction.java
#P org.sophie2.base.model.resources.r4
7 7 import java.util.concurrent.ConcurrentHashMap; 8 8 import java.util.concurrent.ConcurrentMap; 9 9 10 import org.sophie2.base.commons.util.ImmList; 10 11 import org.sophie2.base.commons.util.NaiveImmList; 11 12 import org.sophie2.base.model.resources.r4.ResourceRefR4; 12 13 import org.sophie2.base.model.resources.r4.access.DelegatingAccess; … … 79 80 ResourceRefR4 changeScope = ((DelegatingAccess) access).location; 80 81 81 82 82 final Class<? extends AutoAction> autoActionClass = this.getClass(); 83 Class<? extends AutoAction> autoActionClass = this.getClass(); 84 ImmList<Object> values = getConstructorArgs(this); 83 85 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(); 85 104 105 NaiveImmList<Object> values = NaiveImmList.<Object>getEmpty(); 86 106 try { 87 107 List<Field> fields = AutoAction.Registry.getAccessibleDeclaredFileds( 88 108 autoActionClass); 89 109 for (Field field : fields) { 90 Object value = field.get( this);110 Object value = field.get(autoAction); 91 111 if (value != null && !ProUtil.isImmutable(value.getClass())) { 92 112 value = null; 93 113 } … … 99 119 throw new RuntimeException(e); 100 120 } 101 121 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; 107 123 } 108 124 109 125 /** 110 126 * @author tsachev 111 127 * … … 134 150 } 135 151 List<Field> fieldsList = Collections.<Field>unmodifiableList( 136 152 Arrays.asList(declaredFields)); 137 REGISTRY.putIfAbsent(actionClass, 138 fieldsList); 153 REGISTRY.putIfAbsent(actionClass, fieldsList); 139 154 } 140 155 return REGISTRY.get(actionClass); 141 156 } -
src/main/java/org/sophie2/server/core/persistence/db/DBChangeContext.java
#P org.sophie2.server.core
120 120 * The key to visit,. 121 121 */ 122 122 public KeyValueVisitor(ResourceDAO dao, Key<T> key) { 123 super(dao, key.getValueClass() );123 super(dao, key.getValueClass(), getId()); 124 124 125 125 this.key = key; 126 126 } -
src/main/java/org/sophie2/server/core/persistence/db/ReadKeyVisitor.java
24 24 public final class ReadKeyVisitor<T> extends 25 25 RootAndChildrenVisitor<T> { 26 26 private final Key<T> key; 27 private final RevisionId revisionId;28 29 27 /** 30 28 * Constructs the visitor. 31 29 * … … 38 36 */ 39 37 public ReadKeyVisitor(ResourceDAO dao, 40 38 Key<T> key, RevisionId revisionId) { 41 super(dao, key.getValueClass() );39 super(dao, key.getValueClass(), revisionId); 42 40 this.key = key; 43 this.revisionId = revisionId;44 41 } 45 42 46 43 @Override … … 49 46 // All other types of keys: 50 47 try { 51 48 String dbValue = 52 getDao().findValue(localResPath, keyPath, this.revisionId.getId());49 getDao().findValue(localResPath, keyPath, getRevisionId().getId()); 53 50 54 51 setResult(this.key.getValueClass().cast(ResourceServiceDBImpl.stringToValue(dbValue))); 55 52 } catch (IOException e) { -
src/main/java/org/sophie2/server/core/persistence/db/RootAndChildrenVisitor.java
7 7 import org.sophie2.base.model.resources.r4.immutables.NaiveSubEntryNames; 8 8 import org.sophie2.base.model.resources.r4.immutables.SubEntryNames; 9 9 import org.sophie2.base.model.resources.r4.keys.ChildrenKey; 10 import org.sophie2.base.model.resources.r4.model.RevisionId; 10 11 11 12 /** 12 13 * A key visitor that can handle retrieving of the root and child key values. … … 22 23 private final Class<T> keyValueClass; 23 24 24 25 private T result = null; 26 private final RevisionId revisionId; 25 27 26 28 /** 27 29 * Constructs the visitor. … … 30 32 * A {@link ResourceDAO} to retrieve data from. 31 33 * @param keyValueClass 32 34 * The value class of the key to visit, used for casting. 35 * @param revisionId 36 * The revision to visit keys in. 33 37 */ 34 public RootAndChildrenVisitor(ResourceDAO dao, Class<T> keyValueClass ) {38 public RootAndChildrenVisitor(ResourceDAO dao, Class<T> keyValueClass, RevisionId revisionId) { 35 39 this.dao = dao; 36 40 this.keyValueClass = keyValueClass; 41 this.revisionId = revisionId; 37 42 } 38 43 39 44 @Override 40 45 protected void handleChildrenKey(String localResPath, String keyPath, 41 46 Object value) throws ResponseException { 42 47 // 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); 44 49 45 50 SubEntryNames names = NaiveSubEntryNames.create((Collection<String>) childResources); 46 51 this.result = this.keyValueClass.cast(names); … … 91 96 } 92 97 93 98 /** 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 /** 94 109 * Getter of the result of the visit action. 95 110 * To be called after executing the {@link #visitKey(String, String, Object)} 96 111 * method. -
src/main/resources/distrib/data/queries.properties
25 25 select \ 26 26 r.resource_name \ 27 27 from \ 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 \ 30 where (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 33 46 select_resource_key_names=\ 34 47 select \ 35 48 k.key_path \ -
src/test/java/org/sophie2/server/core/facade/MergeChangesTest.java
1 package org.sophie2.server.core.facade; 2 3 import java.util.List; 4 5 import javax.swing.SwingUtilities; 6 7 import org.junit.Before; 8 import org.junit.Test; 9 import org.sophie2.base.commons.util.ImmColor; 10 import org.sophie2.base.commons.util.ImmList; 11 import org.sophie2.base.commons.util.NaiveImmList; 12 import org.sophie2.base.commons.util.position.ImmSize; 13 import org.sophie2.base.connectivity.BaseConnectivityModule; 14 import org.sophie2.base.connectivity.facade.HistoryEntry; 15 import org.sophie2.base.model.book.BaseModelBookModule; 16 import org.sophie2.base.model.book.BookH; 17 import org.sophie2.base.model.book.interfaces.StyledElement; 18 import org.sophie2.base.model.resources.r4.BaseModelResourcesR4Module; 19 import org.sophie2.base.model.resources.r4.ResourceRefR4; 20 import org.sophie2.base.model.resources.r4.access.ResourceAccess; 21 import org.sophie2.base.model.resources.r4.changes.AutoAction; 22 import org.sophie2.base.model.resources.r4.changes.ModelChange; 23 import org.sophie2.base.model.resources.r4.changes.ResourceChanger; 24 import org.sophie2.base.model.resources.r4.keys.RootKey; 25 import org.sophie2.base.model.resources.r4.keys.UndefinedKey; 26 import org.sophie2.base.model.resources.r4.model.ResourceModel; 27 import org.sophie2.base.model.resources.r4.model.RevisionId; 28 import org.sophie2.base.persistence.BasePersistenceModule; 29 import org.sophie2.core.modularity.FakeModuleRegistry; 30 import org.sophie2.server.core.persistence.access.DBResourceAccess; 31 import org.sophie2.server.core.persistence.db.DBModelTest; 32 import org.sophie2.server.core.persistence.db.ResourceServiceDBImpl; 33 import 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 */ 40 public 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
14 14 import org.sophie2.base.model.resources.r4.keys.Key; 15 15 import org.sophie2.base.model.resources.r4.keys.RootKey; 16 16 import org.sophie2.base.model.resources.r4.keys.UndefinedKey; 17 import org.sophie2.base.model.resources.r4.model.RevisionId; 17 18 import org.sophie2.base.model.resources.r4.resources.ResourceR4; 18 19 import org.sophie2.server.core.persistence.db.jdbc.JdbcTemplate; 19 20 import org.sophie2.server.core.persistence.db.jdbc.ResultSetMapper; … … 414 415 * 415 416 * @param resourcePath 416 417 * The path of the resource which children will be retrieved. 418 * @param revisionId 417 419 * @return 418 420 * The names of the child resources in the DB. 419 421 */ 420 public List<String> findChildResources(String resourcePath ) {422 public List<String> findChildResources(String resourcePath, RevisionId revisionId) { 421 423 String query = SqlQueries.get(SELECT_CHILD_RESOURCE_NAMES); 422 424 423 425 return this.jdbcTemplate.queryForList(query, new StringRowMapper(), 424 resourcePath );426 resourcePath, revisionId.getId(), 1); 425 427 } 426 428 427 429 /**