View Javadoc

1   // Copyright 2008 Thiago H. de Paula Figueiredo
2   //
3   // Licensed under the Apache License, Version 2.0 (the "License");
4   // you may not use this file except in compliance with the License.
5   // You may obtain a copy of the License at
6   //
7   //     http://www.apache.org/licenses/LICENSE-2.0
8   //
9   // Unless required by applicable law or agreed to in writing, software
10  // distributed under the License is distributed on an "AS IS" BASIS,
11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  // See the License for the specific language governing permissions and
13  // limitations under the License.
14  
15  package br.com.arsmachina.tapestrycrud.base;
16  
17  import java.io.Serializable;
18  
19  import org.apache.tapestry5.ComponentResources;
20  import org.apache.tapestry5.EventContext;
21  import org.apache.tapestry5.PrimaryKeyEncoder;
22  import org.apache.tapestry5.annotations.Cached;
23  import org.apache.tapestry5.annotations.OnEvent;
24  import org.apache.tapestry5.annotations.PageDetached;
25  import org.apache.tapestry5.annotations.Retain;
26  import org.apache.tapestry5.beaneditor.BeanModel;
27  import org.apache.tapestry5.corelib.components.Grid;
28  import org.apache.tapestry5.ioc.annotations.Inject;
29  import org.apache.tapestry5.services.BeanModelSource;
30  import org.apache.tapestry5.services.Request;
31  
32  import br.com.arsmachina.tapestrycrud.Constants;
33  import br.com.arsmachina.tapestrycrud.grid.ControllerGridDataSource;
34  import br.com.arsmachina.tapestrycrud.services.PrimaryKeyEncoderSource;
35  
36  /**
37   * Base class for pages that list entity objects. The <code>object</code> property is meant to be
38   * used as the <code>row</code> parameter of the {@link Grid} component.
39   * 
40   * One example of its use can be found in the Ars Machina Project Example Application (<a
41   * href="http://ars-machina.svn.sourceforge.net/viewvc/ars-machina/example/trunk/src/main/java/br/com/arsmachina/example/web/pages/project/ListProject.java?view=markup"
42   * >page class</a>. <a
43   * href="http://ars-machina.svn.sourceforge.net/viewvc/ars-machina/example/trunk/src/main/webapp/project/ListProject.tml?view=markup"
44   * >template</a>).
45   * 
46   * 
47   * @param <T> the entity class related to this encoder.
48   * @param <K> the type of the class' primary key property.
49   * 
50   * @author Thiago H. de Paula Figueiredo
51   */
52  public abstract class BaseListPage<T, K extends Serializable> extends BasePage<T, K> {
53  
54  	@Inject
55  	private ComponentResources componentResources;
56  
57  	@Inject
58  	private Request request;
59  
60  	@Inject
61  	private PrimaryKeyEncoderSource primaryKeyEncoderSource;
62  	
63  	@Retain
64  	private PrimaryKeyEncoder<K, T> primaryKeyEncoder;
65  
66  	@Inject
67  	private BeanModelSource beanModelSource;
68  
69  	private T object;
70  
71  	/**
72  	 * Single constructor of this class.
73  	 */
74  	@SuppressWarnings("unchecked")
75  	public BaseListPage() {
76  		
77  		super();
78  		
79  		primaryKeyEncoder = (PrimaryKeyEncoder<K, T>) primaryKeyEncoderSource.get(getEntityClass());
80  		
81  	}
82  
83  	/**
84  	 * Method used as the <code>source</code> parameter of the {@link Grid} component. This
85  	 * implementation returns <code>new {@link ControllerGridDataSource}(getController())</code>.
86  	 * 
87  	 * @return an {@link Object}.
88  	 */
89  	@SuppressWarnings("unchecked")
90  	@Cached
91  	public Object getObjects() {
92  		return new ControllerGridDataSource(getEntityClass(), getController());
93  	}
94  
95  	/**
96  	 * Returns the value of the <code>object</code> property.
97  	 * 
98  	 * @return a {@link T}.
99  	 */
100 	public T getObject() {
101 		return object;
102 	}
103 
104 	/**
105 	 * Changes the value of the <code>object</code> property.
106 	 * 
107 	 * @param object a {@link T}.
108 	 */
109 	public void setObject(T object) {
110 		this.object = object;
111 	}
112 
113 	/**
114 	 * Adds an <code>action</code> property to the {@link BeanModel}.
115 	 * 
116 	 * @see br.com.arsmachina.tapestrycrud.base.BasePage#getBeanModel()
117 	 */
118 	@SuppressWarnings("unchecked")
119 	public BeanModel<T> getBeanModel() {
120 
121 		final BeanModel<T> beanModel = beanModelSource.createDisplayModel(getEntityClass(),
122 				getMessages());
123 		beanModel.add(Constants.ACTION_PROPERTY_NAME, null);
124 
125 		return beanModel;
126 
127 	}
128 
129 	/**
130 	 * Removes or not a given object. This method only removes an object, using
131 	 * <code>getController().delete(id)</code>, if {@link canRemove(K)} returns <code>true</code>.
132 	 * 
133 	 * @param object a {@link K}.
134 	 */
135 	protected final Object remove(T object) {
136 		
137 		if (object == null) {
138 			setRemoveErrorNotFoundMessage();
139 		}
140 
141 		else if (canRemove(object)) {
142 
143 			getController().delete(object);
144 			setRemoveSuccessMessage();
145 
146 		}
147 		else {
148 			setRemoveErrorNotAllowedMessage();
149 		}
150 
151 		return returnFromDoRemove();
152 
153 	}
154 
155 	/**
156 	 * Defines what {@link #doRemove()} will return.
157 	 * 
158 	 * @return an {@link Object} or <code>null</code>.
159 	 */
160 	protected Object returnFromDoRemove() {
161 
162 		Object returnValue = null;
163 
164 		if (request.isXHR()) {
165 
166 			if (returnZoneOnXHR()) {
167 				returnValue = getFormZone();
168 			}
169 			else {
170 				returnValue = componentResources.getBlock(getFormBlockId());
171 			}
172 
173 		}
174 
175 		return returnValue;
176 
177 	}
178 
179 	/**
180 	 * Sets the remove success message in this page.
181 	 */
182 	protected void setRemoveSuccessMessage() {
183 		setMessage(getMessages().get(Constants.MESSAGE_SUCCESS_REMOVE));
184 	}
185 
186 	/**
187 	 * Sets the remove not done because of lack of priviledge message in this page.
188 	 */
189 	protected void setRemoveErrorNotAllowedMessage() {
190 		setMessage(getMessages().get(Constants.MESSAGE_ERROR_REMOVE_NOT_ALLOWED));
191 	}
192 
193 	/**
194 	 * Sets the remove not done because object not found in this page.
195 	 */
196 	protected void setRemoveErrorNotFoundMessage() {
197 		setMessage(getMessages().get(Constants.MESSAGE_ERROR_REMOVE_NOT_FOUND));
198 	}
199 
200 	/**
201 	 * Tells if a given object can be removed in this context. It must be overriden if you have some
202 	 * rules about when an object can be removed. This implementation just returns <code>true</code>.
203 	 * 
204 	 * @param object a {@link #T}.
205 	 * @return a <code>boolean</code>.
206 	 */
207 	protected boolean canRemove(T object) {
208 		return true;
209 	}
210 
211 	/**
212 	 * Clears the message after it is shown, preventing the message from appearing twice in AJAX
213 	 * actions.
214 	 */
215 	@PageDetached
216 	void clearMessage() {
217 
218 		if (request.isXHR()) {
219 			setMessage(null);
220 		}
221 
222 	}
223 
224 	/**
225 	 * This method listens to the {@link Constants#REMOVE_OBJECT_ACTION} event and removes the
226 	 * corresponding object.
227 	 * 
228 	 * @param context an {@link EventContext}.
229 	 */
230 	@OnEvent(Constants.REMOVE_OBJECT_ACTION)
231 	protected Object remove(EventContext context) {
232 		
233 		K id = context.get(getPrimaryKeyClass(), 0);
234 		final T toBeRemoved = primaryKeyEncoder.toValue(id);
235 		return remove(toBeRemoved);
236 
237 	}
238 
239 	/**
240 	 * Returns the configured {@link PrimaryKeyEncoder} for a given entity class.
241 	 * 
242 	 * @param <X> the type of the entity.
243 	 * @param clasz a {@link Class}.
244 	 * @return a {@link PrimaryKeyEncoder}.
245 	 * @see br.com.arsmachina.tapestrycrud.services.PrimaryKeyEncoderSource#get(java.lang.Class)
246 	 */
247 	protected <X, Y extends Serializable> PrimaryKeyEncoder<Y, X> getPrimaryKeyEncoder(Class<X> clasz) {
248 		return primaryKeyEncoderSource.get(clasz);
249 	}
250 
251 }