001: // Copyright 2006, 2007 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.internal.structure;
016:
017: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
018: import static org.apache.tapestry.ioc.internal.util.Defense.notNull;
019:
020: import java.util.List;
021: import java.util.Locale;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.tapestry.ComponentResources;
025: import org.apache.tapestry.Link;
026: import org.apache.tapestry.internal.services.LinkFactory;
027: import org.apache.tapestry.ioc.internal.util.InternalUtils;
028: import org.apache.tapestry.runtime.Component;
029: import org.apache.tapestry.runtime.PageLifecycleListener;
030: import org.apache.tapestry.services.PersistentFieldBundle;
031: import org.apache.tapestry.services.PersistentFieldManager;
032:
033: public class PageImpl implements Page {
034: private final String _logicalPageName;
035:
036: private final Locale _locale;
037:
038: private final LinkFactory _linkFactory;
039:
040: private final PersistentFieldManager _persistentFieldManager;
041:
042: private ComponentPageElement _rootElement;
043:
044: private final List<PageLifecycleListener> _listeners = newList();
045:
046: private int _dirtyCount;
047:
048: /**
049: * Obtained from the {@link PersistentFieldManager} when first needed, discarded at the end of
050: * the request.
051: */
052: private PersistentFieldBundle _fieldBundle;
053:
054: public PageImpl(String logicalPageName, Locale locale,
055: LinkFactory linkFactory,
056: PersistentFieldManager persistentFieldManager) {
057: _logicalPageName = logicalPageName;
058: _locale = locale;
059: _linkFactory = linkFactory;
060: _persistentFieldManager = persistentFieldManager;
061: }
062:
063: @Override
064: public String toString() {
065: return String.format("Page[%s %s]", _logicalPageName, _locale);
066: }
067:
068: public ComponentPageElement getComponentElementByNestedId(
069: String nestedId) {
070: notNull(nestedId, "nestedId");
071:
072: // TODO: Especially with the addition of all the caseless logic, and with respect to how
073: // forms are implemented, it may be worthwhile to cache the key to element mapping. I think
074: // we're going to do it a lot!
075:
076: ComponentPageElement element = _rootElement;
077:
078: if (InternalUtils.isNonBlank(nestedId)) {
079: for (String id : nestedId.split("\\."))
080: element = element.getEmbeddedElement(id);
081: }
082:
083: return element;
084: }
085:
086: public Locale getLocale() {
087: return _locale;
088: }
089:
090: public void setRootElement(ComponentPageElement component) {
091: _rootElement = component;
092: }
093:
094: public ComponentPageElement getRootElement() {
095: return _rootElement;
096: }
097:
098: public Component getRootComponent() {
099: return _rootElement.getComponent();
100: }
101:
102: public void addLifecycleListener(PageLifecycleListener listener) {
103: _listeners.add(listener);
104: }
105:
106: public boolean detached() {
107: boolean result = _dirtyCount > 0;
108:
109: for (PageLifecycleListener listener : _listeners) {
110: try {
111: listener.containingPageDidDetach();
112: } catch (RuntimeException ex) {
113: getLog().error(
114: StructureMessages.detachFailure(listener, ex),
115: ex);
116: result = true;
117: }
118: }
119:
120: _fieldBundle = null;
121:
122: return result;
123: }
124:
125: public void loaded() {
126: for (PageLifecycleListener listener : _listeners)
127: listener.containingPageDidLoad();
128: }
129:
130: public void attached() {
131: if (_dirtyCount != 0)
132: throw new IllegalStateException(StructureMessages
133: .pageIsDirty(this ));
134:
135: for (PageLifecycleListener listener : _listeners)
136: listener.containingPageDidAttach();
137: }
138:
139: public Log getLog() {
140: return _rootElement.getLog();
141: }
142:
143: public Link createActionLink(ComponentPageElement element,
144: String action, boolean forForm, Object... context) {
145: return _linkFactory.createActionLink(element, action, forForm,
146: context);
147: }
148:
149: public Link createPageLink(String pageName, boolean override,
150: Object... context) {
151: return _linkFactory.createPageLink(pageName, override, context);
152: }
153:
154: public void persistFieldChange(ComponentResources resources,
155: String fieldName, Object newValue) {
156: _persistentFieldManager.postChange(_logicalPageName, resources,
157: fieldName, newValue);
158: }
159:
160: public Object getFieldChange(ComponentPageElement element,
161: String fieldName) {
162: if (_fieldBundle == null)
163: _fieldBundle = _persistentFieldManager
164: .gatherChanges(_logicalPageName);
165:
166: return _fieldBundle.getValue(element.getNestedId(), fieldName);
167: }
168:
169: public void decrementDirtyCount() {
170: _dirtyCount--;
171: }
172:
173: public void incrementDirtyCount() {
174: _dirtyCount++;
175: }
176:
177: public String getLogicalName() {
178: return _logicalPageName;
179: }
180: }
|