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.IRequestCycle; 027 import org.apache.tapestry.engine.IPageRecorder; 028 import org.apache.tapestry.event.ObservedChangeEvent; 029 import org.apache.tapestry.spec.IPropertySpecification; 030 031 /** 032 * @author Howard M. Lewis Ship 033 * @since 4.0 034 */ 035 public class PageRecorderImpl implements IPageRecorder 036 { 037 private String _pageName; 038 039 private IRequestCycle _requestCycle; 040 041 private PropertyPersistenceStrategySource _strategySource; 042 043 private boolean _locked = false; 044 045 private ErrorLog _log; 046 047 public PageRecorderImpl(String pageName, IRequestCycle requestCycle, 048 PropertyPersistenceStrategySource strategySource, ErrorLog log) 049 { 050 Defense.notNull(pageName, "pageName"); 051 Defense.notNull(requestCycle, "requestCycle"); 052 Defense.notNull(strategySource, "strategySource"); 053 Defense.notNull(log, "log"); 054 055 _pageName = pageName; 056 _requestCycle = requestCycle; 057 _strategySource = strategySource; 058 _log = log; 059 } 060 061 public void commit() 062 { 063 _locked = true; 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() 118 .getPropertySpecification(propertyName); 119 120 if (propertySpecification == null) 121 { 122 _log.error( 123 RecordMessages.missingPropertySpecification(propertyName, component), 124 null, 125 null); 126 return null; 127 } 128 129 String name = propertySpecification.getPersistence(); 130 131 // Should check for nulls, but the architecture of the framework pretty much 132 // ensures that we won't get here unless there is a property 133 // and a persistence value for the property. 134 135 try 136 { 137 return _strategySource.getStrategy(name); 138 } 139 catch (ApplicationRuntimeException ex) 140 { 141 _log.error(ex.getMessage(), propertySpecification.getLocation(), ex); 142 143 return null; 144 } 145 } 146 147 }