001: /*
002: * Copyright (c) 2003 - 2007 OpenSubsystems s.r.o. Slovak Republic. All rights reserved.
003: *
004: * Project: OpenChronicle
005: *
006: * $Id: BlogControllerImpl.java,v 1.5 2007/03/05 07:28:33 bastafidli Exp $
007: *
008: * This program is free software; you can redistribute it and/or modify
009: * it under the terms of the GNU General Public License as published by
010: * the Free Software Foundation; version 2 of the License.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021:
022: package org.opensubsystems.blog.logic.impl;
023:
024: import java.rmi.RemoteException;
025:
026: import org.opensubsystems.blog.data.Blog;
027: import org.opensubsystems.blog.data.Entry;
028: import org.opensubsystems.blog.logic.BlogController;
029: import org.opensubsystems.blog.persist.BlogFactory;
030: import org.opensubsystems.blog.persist.EntryFactory;
031: import org.opensubsystems.core.data.DataConstant;
032: import org.opensubsystems.core.data.DataObject;
033: import org.opensubsystems.core.data.ModifiableDataObject;
034: import org.opensubsystems.core.error.OSSException;
035: import org.opensubsystems.core.error.OSSInternalErrorException;
036: import org.opensubsystems.core.logic.ControllerManager;
037: import org.opensubsystems.core.logic.impl.ModifiableDataControllerImpl;
038: import org.opensubsystems.core.persist.BasicDataFactory;
039: import org.opensubsystems.core.persist.DataFactory;
040: import org.opensubsystems.core.persist.DataFactoryManager;
041: import org.opensubsystems.core.util.CallContext;
042: import org.opensubsystems.core.util.GlobalConstants;
043: import org.opensubsystems.patterns.listdata.data.ListDefinition;
044: import org.opensubsystems.patterns.listdata.data.ListOptions;
045: import org.opensubsystems.patterns.listdata.logic.ListController;
046:
047: /**
048: * The main entry point to all business functionality connected with blogs.
049: *
050: * View-type has to be set to local due to bug XDT-867 affecting WebSphere
051: * Refs has to be set to local JNDI name since we do not want to use remote objects.
052: *
053: * @ejb.bean type="Stateless"
054: * name="BlogController"
055: * view-type="local"
056: * jndi-name="org.opensubsystems.blog.logic.BlogControllerRemote"
057: * local-jndi-name="org.opensubsystems.blog.logic.BlogController"
058: * @ejb.interface
059: * local-extends="javax.ejb.EJBLocalObject, org.opensubsystems.blog.logic.BlogController"
060: * extends="javax.ejb.EJBObject, org.opensubsystems.blog.logic.BlogController"
061: *
062: * @jonas.bean ejb-name="BlogController"
063: * jndi-name="org.opensubsystems.blog.logic.BlogControllerRemote"
064: *
065: * @version $Id: BlogControllerImpl.java,v 1.5 2007/03/05 07:28:33 bastafidli Exp $
066: * @author Miro Halas
067: * @code.reviewer Miro Halas
068: * @code.reviewed Initial revision
069: */
070: public class BlogControllerImpl extends ModifiableDataControllerImpl
071: implements BlogController {
072: // Cached values ////////////////////////////////////////////////////////////
073:
074: /**
075: * Factory to use to execute persistence operations.
076: */
077: protected BlogFactory m_blogFactory = null;
078:
079: /**
080: * Factory to use to execute persistence operations.
081: */
082: protected EntryFactory m_entryFactory = null;
083:
084: /**
085: * List controller used to browse list of objects.
086: */
087: protected ListController m_listControl;
088:
089: // Attributes ///////////////////////////////////////////////////////////////
090:
091: /**
092: * Generated serial version id for this class.
093: */
094: private static final long serialVersionUID = -4304971836362014336L;
095:
096: // Constructors /////////////////////////////////////////////////////////////
097:
098: /**
099: * Default constructor.
100: */
101: public BlogControllerImpl() {
102: super ();
103:
104: // Do not cache anything here since if this controller is run as a stateless
105: // session bean the referenced objects may not be ready
106: m_blogFactory = null;
107: m_entryFactory = null;
108: }
109:
110: // Business logic ///////////////////////////////////////////////////////////
111:
112: /**
113: * {@inheritDoc}
114: *
115: * @ejb.interface-method
116: * @ejb.transaction type="Supports"
117: */
118: public Blog get(String strFolder) throws OSSException {
119: return m_blogFactory.get(strFolder);
120: }
121:
122: /**
123: * {@inheritDoc}
124: *
125: * @ejb.interface-method
126: * @ejb.transaction type="Supports"
127: */
128: public Object[] getEntries(int iBlogId, int iPageNumber)
129: throws OSSException {
130: Object[] returnValue = { null, null };
131:
132: try {
133: Object[] listInfo;
134:
135: listInfo = m_listControl.getExactPage(constructListOptions(
136: iBlogId, iPageNumber));
137: if (listInfo != null) {
138: // We change the order to keep it consistent with getWithEntries
139: // which returned array without ListOptions with v1 so we added
140: // ListOptions as a new element in the array and now the list
141: // is before the ListOptions
142: returnValue[0] = listInfo[1];
143: returnValue[1] = listInfo[0];
144: }
145: } catch (RemoteException rExc) {
146: // We cannot propagate this exception otherwise XDoclet would generate
147: // the local interface incorrectly since it would include the declared
148: // RemoteException in it (to propagate we would have to declare it)
149: throw new OSSInternalErrorException(
150: "Remote error has occured", rExc);
151: }
152:
153: return returnValue;
154: }
155:
156: /**
157: * {@inheritDoc}
158: *
159: * @ejb.interface-method
160: * @ejb.transaction type="Supports"
161: */
162: public Object[] getWithEntries(String strFolder, int iPageNumber)
163: throws OSSException {
164: Object[] returnValue = { null, null, null };
165: Blog blog;
166:
167: // This demonstrate important technique and that is session facade pattern
168: // One call to controller is used to fetch multiple pieces of data.
169: // This is important if controller is remote from the presentation tier
170: // and then we want to perform only as little remote calls as possible.
171: blog = m_blogFactory.get(strFolder);
172: if (blog != null) {
173: returnValue[0] = blog;
174: try {
175: Object[] listInfo;
176:
177: listInfo = m_listControl
178: .getExactPage(constructListOptions(
179: blog.getId(), iPageNumber));
180: if (listInfo != null) {
181: returnValue[1] = listInfo[1];
182: returnValue[2] = listInfo[0];
183: }
184: } catch (RemoteException rExc) {
185: // We cannot propagate this exception otherwise XDoclet would generate
186: // the local interface incorrectly since it would include the declared
187: // RemoteException in it (to propagate we would have to declare it)
188: throw new OSSInternalErrorException(
189: "Remote error has occured", rExc);
190: }
191: }
192:
193: return returnValue;
194: }
195:
196: /**
197: * {@inheritDoc}
198: *
199: * @ejb.interface-method
200: * @ejb.transaction type="Supports"
201: */
202: public Object[] getWithEntry(String strFolder, int iEntryId)
203: throws OSSException {
204: Object[] returnValue = { null, null };
205: Blog blog;
206: Entry entry;
207:
208: // This demonstrate important technique and that is session facade pattern
209: // One call to controller is used to fetch multiple pieces of data.
210: // This is important if controller is remote from the presentation tier
211: // and then we want to perform only as little remote calls as possible.
212:
213: // TODO: Performace: Here we are making two calls to the database, one for
214: // entry and one for blog. But the relationship is 1:1 so we could fetch
215: // entry and it's blog with one call and then just construct two objects
216: // from the one result set.
217:
218: // Performance improvement: Since we know the entry ID try to load
219: // it first and then find the blog by its id instead of searching by folder
220: entry = (Entry) m_entryFactory.get(iEntryId, CallContext
221: .getInstance().getCurrentDomainId());
222: if (entry != null) {
223: returnValue[1] = entry;
224: if (entry.getParentId() != DataObject.NEW_ID) {
225: // Entry was found, now find the blog faster way
226: blog = (Blog) m_blogFactory.get(entry.getParentId(),
227: CallContext.getInstance().getCurrentDomainId());
228:
229: if (GlobalConstants.ERROR_CHECKING) {
230: assert blog != null : "Blog cannot be null when entry was found";
231: }
232: } else {
233: // The entry doesn't exist yet so still have to find blog by the folder
234: blog = m_blogFactory.get(strFolder);
235: }
236: } else {
237: // Entry wasn't found but we can still try to find blog by the folder
238: blog = m_blogFactory.get(strFolder);
239: }
240: if (blog != null) {
241: returnValue[0] = blog;
242: }
243:
244: return returnValue;
245: }
246:
247: /**
248: * {@inheritDoc}
249: *
250: * @ejb.interface-method
251: * @ejb.transaction type="Supports"
252: */
253: public Object[] getWithEntry(int iBlogId, int iEntryId)
254: throws OSSException {
255: Object[] returnValue = { null, null };
256: Blog blog;
257: Entry entry;
258:
259: // This demonstrate important technique and that is session facade pattern
260: // One call to controller is used to fetch multiple pieces of data.
261: // This is important if controller is remote from the presentation tier
262: // and then we want to perform only as little remote calls as possible.
263:
264: // TODO: Performace: Here we are making two calls to the database, one for
265: // entry and one for blog. But the relationship is 1:1 so we could fetch
266: // entry and it's blog with one call and then just construct two objects
267: // from the one result set.
268:
269: blog = (Blog) m_blogFactory.get(iBlogId, CallContext
270: .getInstance().getCurrentDomainId());
271: if (blog != null) {
272: returnValue[0] = blog;
273: entry = (Entry) m_entryFactory.get(iEntryId, CallContext
274: .getInstance().getCurrentDomainId());
275: if (entry != null) {
276: if (iEntryId == DataObject.NEW_ID) {
277: entry.setParentId(iBlogId);
278: }
279: returnValue[1] = entry;
280: }
281: }
282:
283: return returnValue;
284: }
285:
286: /**
287: * {@inheritDoc}
288: *
289: * @ejb.interface-method
290: * @ejb.transaction type="Supports"
291: */
292: public Object[] getPage(int iPageNumber) throws OSSException {
293: Object[] returnValue = { null, null };
294: Object[] listInfo;
295:
296: try {
297: listInfo = m_listControl
298: .getExactPage(constructListOptions(iPageNumber));
299: if (listInfo != null) {
300: // We change the order to keep it consistent with getWithEntries
301: // which returned array without ListOptions with v1 so we added
302: // ListOptions as a new element in the array and now the list
303: // is before the ListOptions
304: returnValue[0] = listInfo[1];
305: returnValue[1] = listInfo[0];
306: }
307: } catch (RemoteException rExc) {
308: // We cannot propagate this exception otherwise XDoclet would generate
309: // the local interface incorrectly since it would include the declared
310: // RemoteException in it (to propagate we would have to declare it)
311: throw new OSSInternalErrorException(
312: "Remote error has occured", rExc);
313: }
314:
315: return returnValue;
316: }
317:
318: /**
319: * {@inheritDoc}
320: *
321: * @ejb.interface-method
322: * @ejb.transaction type="Required"
323: */
324: public void deleteEntry(int iBlogEntryId) throws OSSException {
325: m_entryFactory.delete(iBlogEntryId, CallContext.getInstance()
326: .getCurrentDomainId());
327: }
328:
329: /**
330: * {@inheritDoc}
331: *
332: * @ejb.interface-method
333: * @ejb.transaction type="Supports"
334: */
335: public void constructor() throws OSSException {
336: m_blogFactory = (BlogFactory) DataFactoryManager
337: .getInstance(BlogFactory.class);
338: m_entryFactory = (EntryFactory) DataFactoryManager
339: .getInstance(EntryFactory.class);
340: m_listControl = (ListController) ControllerManager
341: .getInstance(ListController.class);
342: }
343:
344: // Helper methods ///////////////////////////////////////////////////////////
345:
346: /**
347: * {@inheritDoc}
348: */
349: protected DataFactory getDataFactory() {
350: // Blog is the default entity for this controller so return the blog factory
351: return m_blogFactory;
352: }
353:
354: /**
355: * {@inheritDoc}
356: */
357: protected BasicDataFactory getDataFactory(DataObject data) {
358: BasicDataFactory factory = null;
359:
360: if (GlobalConstants.ERROR_CHECKING) {
361: assert data != null : "Cannot return factory for null data object";
362: }
363:
364: if (data instanceof Blog) {
365: factory = m_blogFactory;
366: } else if (data instanceof Entry) {
367: factory = m_entryFactory;
368: } else {
369: if (GlobalConstants.ERROR_CHECKING) {
370: assert false : "Cannot return factory for unrecognized data type "
371: + data.getClass().getName();
372: }
373: }
374:
375: return factory;
376: }
377:
378: /**
379: * Construct list options object to retrieve specified page with list of blogs.
380: *
381: * @param iPageNumber - specified page with list of blogs to retrieve
382: * @return ListOptions - list options that can be used to call ListController
383: * getExactPage method to retrieve specified page with
384: * list of blogs
385: */
386: protected ListOptions constructListOptions(int iPageNumber) {
387: ListOptions options = new ListOptions(BlogFactory.class,
388: null, // At this time we do not support any list definitions
389: ListDefinition.DEFAULT_PAGE_SIZE,
390: 0, // We don't know what is the actual list size
391: Blog.DEFAULT_LIST_SORT_COLUMNS,
392: Blog.DEFAULT_LIST_SORT_ORDER, 0, // At this time we do not support client side sorting
393: null, // At this time we do not support client side sorting
394: 0, // We don't know what is the begin position
395: 0, // We don't know what is the end position
396: iPageNumber, 0, // We don't allow client to
397: DataConstant.NO_DATA_TYPE, // blog doesn't have parent
398: DataObject.NEW_ID, // blog doens't have parent
399: null, // At this time we do not support client side selection
400: null, // At this time we do not support client side highlighting
401: Blog.DEFAULT_LIST_COLUMNS, null, // At this time we do not support excluding any items
402: false, // We want all blogs
403: false, // At this time we do not support client side selection
404: CallContext.getInstance().getCurrentDomainId());
405:
406: return options;
407: }
408:
409: /**
410: * Construct list options object to retrieve specified page with list of
411: * blogs entries for the specified blog.
412: *
413: * @param iBlogId - if of blog for which to retrieve page with entries
414: * @param iPageNumber - specified page with list of blogs entries to retrieve
415: * @return ListOptions - list options that can be used to call ListController
416: * getExactPage method to retrieve specified page with
417: * list of blogs entries for the specified blog.
418: */
419: protected ListOptions constructListOptions(int iBlogId,
420: int iPageNumber) {
421: ListOptions options = new ListOptions(EntryFactory.class,
422: null, // At this time we do not support any list definitions
423: ListDefinition.DEFAULT_PAGE_SIZE,
424: 0, // We don't know what is the actual list size
425: Entry.DEFAULT_LIST_SORT_COLUMNS,
426: Entry.DEFAULT_LIST_SORT_ORDER, 0, // At this time we do not support client side sorting
427: null, // At this time we do not support client side sorting
428: 0, // We don't know what is the begin position
429: 0, // We don't know what is the end position
430: iPageNumber, 0, // We don't allow client to
431: DataConstant.BLOG_DATA_TYPE, // blog entrys' parent is blog
432: iBlogId, // blog id specifies the blog for which to retrieve entries
433: null, // At this time we do not support client side selection
434: null, // At this time we do not support client side highlighting
435: Entry.DEFAULT_LIST_COLUMNS, null, // At this time we do not support excluding any items
436: false, // We want all blogs
437: false, // At this time we do not support client side selection
438: CallContext.getInstance().getCurrentDomainId());
439:
440: return options;
441: }
442:
443: // XDoclet EJB bug workaround methods ///////////////////////////////////////
444: // TODO: Bug: XDoclet: 1.2.3: XDoclet incorrectly generates interfaces for
445: // these methods so override the to force it to generate correct information
446: // Verified on 8/30/2006 with JBoxx 4.0.4
447:
448: /**
449: * {@inheritDoc}
450: *
451: * @ejb.interface-method
452: * @ejb.transaction type="Required"
453: */
454: public ModifiableDataObject save(ModifiableDataObject data)
455: throws OSSException {
456: return super .save(data);
457: }
458:
459: /**
460: * {@inheritDoc}
461: *
462: * @ejb.interface-method
463: * @ejb.transaction type="Required"
464: */
465: public DataObject create(DataObject data) throws OSSException {
466: return super .create(data);
467: }
468:
469: /**
470: * {@inheritDoc}
471: *
472: * @ejb.interface-method
473: * @ejb.transaction type="Required"
474: */
475: public void delete(int iId) throws OSSException {
476: super .delete(iId);
477: }
478:
479: /**
480: * {@inheritDoc}
481: *
482: * @ejb.interface-method
483: * @ejb.transaction type="Supports"
484: */
485: public DataObject get(int iId) throws OSSException {
486: return super.get(iId);
487: }
488: }
|