001 // Copyright 2005 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 015 package org.apache.tapestry.record; 016 017 import java.util.Collection; 018 import java.util.Iterator; 019 020 import org.apache.hivemind.ApplicationRuntimeException; 021 import org.apache.hivemind.ErrorLog; 022 import org.apache.hivemind.util.Defense; 023 import org.apache.hivemind.util.PropertyUtils; 024 import org.apache.tapestry.IComponent; 025 import org.apache.tapestry.IPage; 026 import org.apache.tapestry.engine.IPageRecorder; 027 import org.apache.tapestry.event.ObservedChangeEvent; 028 import org.apache.tapestry.spec.IPropertySpecification; 029 030 /** 031 * @author Howard M. Lewis Ship 032 * @since 4.0 033 */ 034 public class PageRecorderImpl implements IPageRecorder 035 { 036 037 private String _pageName; 038 039 private PropertyPersistenceStrategySource _strategySource; 040 041 private boolean _locked = false; 042 043 private ErrorLog _log; 044 045 public PageRecorderImpl(String pageName, PropertyPersistenceStrategySource strategySource, ErrorLog log) 046 { 047 Defense.notNull(pageName, "pageName"); 048 Defense.notNull(strategySource, "strategySource"); 049 Defense.notNull(log, "log"); 050 051 _pageName = pageName; 052 _strategySource = strategySource; 053 _log = log; 054 } 055 056 public void commit() 057 { 058 _locked = true; 059 } 060 061 public boolean isLocked() 062 { 063 return _locked; 064 } 065 066 public Collection getChanges() 067 { 068 return _strategySource.getAllStoredChanges(_pageName); 069 } 070 071 public void rollback(IPage page) 072 { 073 Collection changes = getChanges(); 074 075 Iterator i = changes.iterator(); 076 077 while(i.hasNext()) 078 { 079 PropertyChange change = (PropertyChange) i.next(); 080 081 applyChange(page, change); 082 } 083 } 084 085 private void applyChange(IPage page, PropertyChange change) 086 { 087 String idPath = change.getComponentPath(); 088 089 IComponent component = (idPath == null) ? page : page.getNestedComponent(idPath); 090 091 PropertyUtils.write(component, change.getPropertyName(), change.getNewValue()); 092 } 093 094 public void observeChange(ObservedChangeEvent event) 095 { 096 IComponent component = event.getComponent(); 097 String propertyName = event.getPropertyName(); 098 099 if (_locked) 100 { 101 _log.error(RecordMessages.recorderLocked(propertyName, component), null, null); 102 return; 103 } 104 105 PropertyPersistenceStrategy strategy = findStrategy(component, propertyName); 106 107 if (strategy != null) 108 strategy.store(_pageName, component.getIdPath(), propertyName, event.getNewValue()); 109 } 110 111 // package private for testing 112 113 PropertyPersistenceStrategy findStrategy(IComponent component, String propertyName) 114 { 115 // So much for Law of Demeter! 116 117 IPropertySpecification propertySpecification = component.getSpecification().getPropertySpecification(propertyName); 118 119 if (propertySpecification == null) 120 { 121 _log.error(RecordMessages.missingPropertySpecification(propertyName, component), null, null); 122 return null; 123 } 124 125 String name = propertySpecification.getPersistence(); 126 127 // Should check for nulls, but the architecture of the framework pretty 128 // much 129 // ensures that we won't get here unless there is a property 130 // and a persistence value for the property. 131 132 try 133 { 134 return _strategySource.getStrategy(name); 135 } 136 catch (ApplicationRuntimeException ex) 137 { 138 _log.error(ex.getMessage(), propertySpecification.getLocation(), ex); 139 return null; 140 } 141 } 142 143 }