001: package org.contineo.web.document;
002:
003: import com.icesoft.faces.context.effects.JavascriptContext;
004:
005: import org.apache.commons.lang.StringUtils;
006: import org.apache.commons.logging.Log;
007: import org.apache.commons.logging.LogFactory;
008:
009: import org.contineo.core.CryptBean;
010: import org.contineo.core.document.Document;
011: import org.contineo.core.document.DownloadTicket;
012: import org.contineo.core.document.History;
013: import org.contineo.core.document.dao.DocumentDAO;
014: import org.contineo.core.document.dao.DownloadTicketDAO;
015: import org.contineo.core.document.dao.HistoryDAO;
016: import org.contineo.core.i18n.DateBean;
017: import org.contineo.core.security.ExtMenu;
018: import org.contineo.core.security.Menu;
019: import org.contineo.core.security.dao.MenuDAO;
020:
021: import org.contineo.util.Context;
022:
023: import org.contineo.web.SessionManagement;
024: import org.contineo.web.StyleBean;
025: import org.contineo.web.i18n.Messages;
026: import org.contineo.web.navigation.MenuBarBean;
027: import org.contineo.web.navigation.MenuItem;
028: import org.contineo.web.navigation.PageContentBean;
029: import org.contineo.web.upload.InputFileBean;
030: import org.contineo.web.util.Constants;
031:
032: import java.text.DateFormat;
033:
034: import java.util.ArrayList;
035: import java.util.Date;
036: import java.util.Map;
037:
038: import javax.faces.application.Application;
039: import javax.faces.context.FacesContext;
040: import javax.faces.event.ActionEvent;
041:
042: import javax.servlet.http.HttpServletRequest;
043:
044: /**
045: * The <code>DocumentRecord</code> class contains the base information for an
046: * entry in a data table. This class is meant to represent a model and should
047: * only contain base document data <p/>
048: *
049: * @author Marco Meschieri
050: * @version $Id: DocumentRecord.java,v 1.17 2006/08/29 16:33:46 marco Exp $
051: * @since 3.0
052: */
053: public class DocumentRecord extends MenuBarBean {
054: protected static Log log = LogFactory.getLog(DocumentRecord.class);
055: public static final String SPACER_IMAGE = StyleBean.XP_SPACER_ICON;
056:
057: // style for column that holds expand/contract image toggle, in the sales
058: // record row.
059: protected String indentStyleClass = "";
060:
061: // style for all other columns in the sales record row.
062: protected String rowStyleClass = "";
063:
064: // Images used to represent expand/contract, spacer by default
065: protected String expandImage = SPACER_IMAGE; // arrow points right
066: protected String contractImage = SPACER_IMAGE; // arrow point down
067:
068: // image which will be drawn to screen
069: protected String expandContractImage = SPACER_IMAGE;
070:
071: // callback to list which contains all data in the dataTable. This callback
072: // is needed so that a node can be set in the expanded state at construction
073: // time.
074: protected ArrayList parentDocumentsList;
075:
076: // indicates if node is in expanded state.
077: protected boolean isExpanded;
078:
079: // indicates if node is selected
080: protected boolean selected = false;
081: private ExtMenu menu;
082: private Document document;
083:
084: // list of child documents
085: protected ArrayList<DocumentRecord> childRecords = new ArrayList<DocumentRecord>();
086: private MenuItem contextMenu;
087:
088: /**
089: * <p>
090: * Creates a new <code>DocumentRecord</code>. This constructor should be
091: * used when creating DocumentRecord which will contain children
092: * </p>
093: *
094: * @param isExpanded true, indicates that the specified node will be
095: * expanded by default; otherwise, false.
096: */
097: public DocumentRecord(ExtMenu menu, String indentStyleClass,
098: String rowStyleClass, String expandImage,
099: String contractImage, ArrayList parentDocumentsList,
100: boolean isExpanded) {
101: this .menu = menu;
102:
103: DocumentDAO docDao = (DocumentDAO) Context.getInstance()
104: .getBean(DocumentDAO.class);
105: this .document = docDao.findByMenuId(menu.getMenuId());
106:
107: this .indentStyleClass = indentStyleClass;
108: this .rowStyleClass = rowStyleClass;
109: this .expandImage = expandImage;
110: this .contractImage = contractImage;
111: this .parentDocumentsList = parentDocumentsList;
112: this .parentDocumentsList.add(this );
113: this .isExpanded = isExpanded;
114:
115: // update the default state of the node.
116: if (this .isExpanded) {
117: expandContractImage = contractImage;
118: expandNodeAction();
119: } else {
120: expandContractImage = expandImage;
121: }
122: }
123:
124: /**
125: * <p>
126: * Creates a new <code>DocumentRecord</code>. This constructor should be
127: * used when creating a DocumentRecord which will be a child of some other
128: * DocumentRecord.
129: * </p>
130: * <p/>
131: * <p>
132: * The created DocumentRecord has no image states defined.
133: * </p>
134: *
135: * @param document
136: * @param indentStyleClass
137: * @param rowStyleClass
138: */
139: public DocumentRecord(ExtMenu menu, String indentStyleClass,
140: String rowStyleClass) {
141: this .menu = menu;
142:
143: DocumentDAO docDao = (DocumentDAO) Context.getInstance()
144: .getBean(DocumentDAO.class);
145: this .document = docDao.findByMenuId(menu.getMenuId());
146: this .indentStyleClass = indentStyleClass;
147: this .rowStyleClass = rowStyleClass;
148: }
149:
150: public ExtMenu getMenu() {
151: return menu;
152: }
153:
154: public Document getDocument() {
155: return document;
156: }
157:
158: /**
159: * Gets the description of the record
160: *
161: * @return description of the record
162: */
163: public String getDescription() {
164: return menu.getMenuText();
165: }
166:
167: public String getDisplayDescription() {
168: return StringUtils.abbreviate(menu.getMenuText(), 68);
169: }
170:
171: public ArrayList<DocumentRecord> getChildRecords() {
172: return childRecords;
173: }
174:
175: /**
176: * Utility method to add all child nodes to the parent dataTable list.
177: */
178: private void expandNodeAction() {
179: if ((childRecords != null) && (childRecords.size() > 0)) {
180: // get index of current node
181: int index = parentDocumentsList.indexOf(this );
182:
183: // add all items in childRecords to the parent list
184: parentDocumentsList.addAll(index + 1, childRecords);
185: }
186: }
187:
188: /**
189: * Utility method to remove all child nodes from the parent dataTable list.
190: */
191: private void contractNodeAction() {
192: if ((childRecords != null) && (childRecords.size() > 0)) {
193: // add all items in childRecords to the parent list
194: parentDocumentsList.removeAll(childRecords);
195: }
196: }
197:
198: /**
199: * Adds a child sales record to this sales group.
200: *
201: * @param documentRecord child document record to add to this record.
202: */
203: public void addChildRecord(DocumentRecord documentRecord) {
204: if ((this .childRecords != null) && (documentRecord != null)) {
205: this .childRecords.add(documentRecord);
206:
207: if (isExpanded) {
208: // to keep elements in order, remove all
209: contractNodeAction();
210: // then add them again.
211: expandNodeAction();
212: }
213: }
214: }
215:
216: /**
217: * Toggles the expanded state of this DocumentRecord.
218: */
219: public void toggleSubGroupAction(ActionEvent event) {
220: // toggle expanded state
221: isExpanded = !isExpanded;
222:
223: // add sub elements to list
224: if (isExpanded) {
225: expandContractImage = contractImage;
226: expandNodeAction();
227: }
228: // remove items from list
229: else {
230: expandContractImage = expandImage;
231: contractNodeAction();
232: }
233: }
234:
235: /**
236: * Gets the style class name used to define the first column of a document
237: * record row. This first column is where a expand/contract image is placed.
238: *
239: * @return indent style class as defined in css file
240: */
241: public String getIndentStyleClass() {
242: return indentStyleClass;
243: }
244:
245: /**
246: * Gets the style class name used to define all other columns in the
247: * document record row, except the first column.
248: *
249: * @return style class as defined in css file
250: */
251: public String getRowStyleClass() {
252: return rowStyleClass;
253: }
254:
255: /**
256: * Gets the image which will represent either the expanded or contracted
257: * state of the <code>DocumentRecord</code>.
258: *
259: * @return name of image to draw
260: */
261: public String getExpandContractImage() {
262: return expandContractImage;
263: }
264:
265: public int getId() {
266: return document.getDocId();
267: }
268:
269: public int getMenuId() {
270: return document.getMenuId();
271: }
272:
273: public boolean isSelected() {
274: return selected;
275: }
276:
277: public void setSelected(boolean selected) {
278: this .selected = selected;
279: }
280:
281: public String getIcon() {
282: return getMenu().getMenuIcon();
283: }
284:
285: @Override
286: public boolean equals(Object arg0) {
287: if ((arg0 == null) || (document == null)) {
288: return false;
289: } else {
290: return document.equals(((DocumentRecord) arg0)
291: .getDocument());
292: }
293: }
294:
295: /**
296: * Creates the context menu associated with this record
297: *
298: * @see org.contineo.web.navigation.MenuBarBean#createMenuItems()
299: */
300: protected void createMenuItems() {
301: model.clear();
302:
303: FacesContext facesContext = FacesContext.getCurrentInstance();
304: Map session = facesContext.getExternalContext().getSessionMap();
305: String username = (String) session.get(Constants.AUTH_USERNAME);
306:
307: ExtMenu menu = getMenu();
308:
309: contextMenu = createMenuItem(" ",
310: "context-" + menu.getMenuId(), null,
311: "#{documentRecord.noaction}", null, StyleBean
312: .getImagePath("options_small.png"), true, null,
313: null);
314: model.add(contextMenu);
315:
316: if (menu.getWritable()) {
317: if ((menu.getDocStatus() == Document.DOC_CHECKED_OUT)
318: && menu.getCheckoutUser().equals(username)) {
319: contextMenu.getChildren().add(
320: createMenuItem(Messages
321: .getMessage("msg.jsp.checkin"),
322: "checkin-" + menu.getMenuId(), null,
323: "#{documentRecord.checkin}", null,
324: StyleBean.getImagePath("/checkin.png"),
325: true, null, null));
326: } else if (menu.getDocStatus() == Document.DOC_CHECKED_IN) {
327: contextMenu.getChildren().add(
328: createMenuItem(Messages
329: .getMessage("msg.jsp.checkout"),
330: "checkout-" + menu.getMenuId(), null,
331: "#{documentRecord.checkout}", null,
332: StyleBean.getImagePath("checkout.png"),
333: true, null, null));
334: }
335:
336: contextMenu.getChildren().add(
337: createMenuItem(Messages
338: .getMessage("msg.jsp.foldercontent.edit"),
339: "edit-" + menu.getMenuId(), null,
340: "#{documentRecord.edit}", null, StyleBean
341: .getImagePath("edit.png"), true,
342: null, null));
343: contextMenu
344: .getChildren()
345: .add(
346: createMenuItem(
347: Messages
348: .getMessage("msg.jsp.foldercontent.rights"),
349: "rights-" + menu.getMenuId(), null,
350: "#{documentRecord.rights}", null,
351: StyleBean.getImagePath("auth.png"),
352: true, null, null));
353: }
354:
355: if (menu.getMenuType() == Menu.MENUTYPE_FILE) {
356: contextMenu.getChildren().add(
357: createMenuItem(Messages
358: .getMessage("msg.jsp.download"),
359: "download-" + menu.getMenuId(), null, null,
360: "download?menuId=" + menu.getMenuId(),
361: StyleBean.getImagePath("download.png"),
362: true, "_blank", null));
363: contextMenu.getChildren().add(
364: createMenuItem(Messages
365: .getMessage("msg.jsp.versions"),
366: "versions-" + menu.getMenuId(), null,
367: "#{documentRecord.versions}", null,
368: StyleBean.getImagePath("versions.png"),
369: true, "_blank", null));
370: contextMenu.getChildren().add(
371: createMenuItem(Messages
372: .getMessage("msg.jsp.similardocs"),
373: "similar-" + menu.getMenuId(), null,
374: "#{searchForm.searchSimilar}", null,
375: StyleBean.getImagePath("similar.png"),
376: true, "_blank", null));
377: contextMenu.getChildren().add(
378: createMenuItem(Messages
379: .getMessage("msg.jsp.discuss"), "articles-"
380: + menu.getMenuId(), null,
381: "#{documentRecord.articles}", null,
382: StyleBean.getImagePath("group.png"), true,
383: "_blank", null));
384: contextMenu.getChildren().add(
385: createMenuItem(Messages
386: .getMessage("msg.jsp.sendasemail"),
387: "sendasmail-" + menu.getMenuId(), null,
388: "#{documentRecord.sendAsEmail}", null,
389: StyleBean.getImagePath("editmail.png"),
390: true, "_blank", null));
391: contextMenu.getChildren().add(
392: createMenuItem(Messages
393: .getMessage("msg.jsp.sendticket"),
394: "sendticket-" + menu.getMenuId(), null,
395: "#{documentRecord.sendAsTicket}", null,
396: StyleBean.getImagePath("ticket.png"), true,
397: "_blank", null));
398: contextMenu.getChildren().add(
399: createMenuItem(Messages
400: .getMessage("msg.jsp.foldercontent.info"),
401: "info-" + menu.getMenuId(), null,
402: "#{documentRecord.info}", null, StyleBean
403: .getImagePath("info.png"), true,
404: "_blank", null));
405: contextMenu.getChildren().add(
406: createMenuItem(Messages
407: .getMessage("msg.jsp.history"), "history-"
408: + menu.getMenuId(), null,
409: "#{documentRecord.history}", null,
410: StyleBean.getImagePath("history.png"),
411: true, "_blank", null));
412: }
413: }
414:
415: public String noaction() {
416: return null;
417: }
418:
419: public String edit() {
420: // Show the proper panel
421: Application application = FacesContext.getCurrentInstance()
422: .getApplication();
423: DocumentNavigation documentNavigation = ((DocumentNavigation) application
424: .createValueBinding("#{documentNavigation}").getValue(
425: FacesContext.getCurrentInstance()));
426: documentNavigation.setSelectedPanel(new PageContentBean(
427: "updateDocument"));
428:
429: // Now initialize the form
430: DocumentEditForm docForm = ((DocumentEditForm) application
431: .createValueBinding("#{documentForm}").getValue(
432: FacesContext.getCurrentInstance()));
433: docForm.reset();
434: docForm.init(this );
435: docForm.setReadOnly(false);
436:
437: return null;
438: }
439:
440: /**
441: * Executes the checkout and the related document's download
442: */
443: public String checkout() {
444: String username = SessionManagement.getUsername();
445: MenuDAO mdao = (MenuDAO) Context.getInstance().getBean(
446: MenuDAO.class);
447: DocumentDAO ddao = (DocumentDAO) Context.getInstance().getBean(
448: DocumentDAO.class);
449:
450: if (SessionManagement.isValid()) {
451: try {
452: if (mdao.isWriteEnable(document.getMenuId(), username)) {
453: if (document.getDocStatus() == Document.DOC_CHECKED_IN) {
454: Menu menu = mdao.findByPrimaryKey(document
455: .getMenuId());
456:
457: if (document.getDocStatus() == Document.DOC_CHECKED_IN) {
458: document.setCheckoutUser(username);
459: document
460: .setDocStatus(Document.DOC_CHECKED_OUT);
461: document.setMenu(menu);
462: ddao.store(document);
463:
464: /* create historycheckout entry */
465: History history = new History();
466: history.setDocId(document.getDocId());
467: history.setDate(DateBean.toCompactString());
468: history.setUsername(username);
469: history.setEvent(History.CHECKOUT);
470:
471: HistoryDAO historyDAO = (HistoryDAO) Context
472: .getInstance().getBean(
473: HistoryDAO.class);
474: historyDAO.store(history);
475:
476: JavascriptContext
477: .addJavascriptCall(
478: FacesContext
479: .getCurrentInstance(),
480: "window.open(\""
481: + FacesContext
482: .getCurrentInstance()
483: .getExternalContext()
484: .getRequestContextPath()
485: + "/download?menuId="
486: + document
487: .getMenuId()
488: + "\", 'download');");
489: } else {
490: Messages
491: .addLocalizedError("errors.noaccess");
492: }
493: } else {
494: Messages.addLocalizedError("errors.noaccess");
495: }
496: } else {
497: Messages.addLocalizedError("errors.noaccess");
498: }
499: } catch (Exception ex) {
500: log.error(ex.getMessage(), ex);
501: Messages.addLocalizedError("errors.error");
502: }
503: } else {
504: return "login";
505: }
506:
507: return null;
508: }
509:
510: /**
511: * Executes the checkin and the related document's download
512: */
513: public String checkin() {
514: if (SessionManagement.isValid()) {
515: // Show the proper panel
516: Application application = FacesContext.getCurrentInstance()
517: .getApplication();
518: DocumentNavigation documentNavigation = ((DocumentNavigation) application
519: .createValueBinding("#{documentNavigation}")
520: .getValue(FacesContext.getCurrentInstance()));
521: documentNavigation.setSelectedPanel(new PageContentBean(
522: "checkin"));
523:
524: // Now initialize the edit form
525: DocumentEditForm docForm = ((DocumentEditForm) application
526: .createValueBinding("#{documentForm}").getValue(
527: FacesContext.getCurrentInstance()));
528: docForm.reset();
529: docForm.init(this );
530:
531: InputFileBean fileForm = ((InputFileBean) application
532: .createValueBinding("#{inputFile}").getValue(
533: FacesContext.getCurrentInstance()));
534: fileForm.reset();
535: } else {
536: return "login";
537: }
538:
539: return null;
540: }
541:
542: /**
543: * Shows all versions of this document
544: */
545: public String versions() {
546: String username = SessionManagement.getUsername();
547: MenuDAO mdao = (MenuDAO) Context.getInstance().getBean(
548: MenuDAO.class);
549:
550: if (SessionManagement.isValid()) {
551: try {
552: if (mdao.isWriteEnable(document.getMenuId(), username)) {
553: Application application = FacesContext
554: .getCurrentInstance().getApplication();
555: VersionsRecordsManager versionsManager = ((VersionsRecordsManager) application
556: .createValueBinding(
557: "#{versionsRecordsManager}")
558: .getValue(FacesContext.getCurrentInstance()));
559: versionsManager.selectDocument(document);
560:
561: DocumentNavigation documentNavigation = ((DocumentNavigation) application
562: .createValueBinding("#{documentNavigation}")
563: .getValue(FacesContext.getCurrentInstance()));
564: documentNavigation
565: .setSelectedPanel(new PageContentBean(
566: "versions"));
567: } else {
568: Messages.addError(Messages
569: .getMessage("errors.noaccess"));
570: }
571: } catch (Exception ex) {
572: log.error(ex.getMessage(), ex);
573: Messages.addError(Messages.getMessage("errors.error"));
574: }
575: } else {
576: return "login";
577: }
578:
579: return null;
580: }
581:
582: /**
583: * Shows rights for this document
584: */
585: public String rights() {
586: String username = SessionManagement.getUsername();
587: MenuDAO mdao = (MenuDAO) Context.getInstance().getBean(
588: MenuDAO.class);
589:
590: if (SessionManagement.isValid()) {
591: try {
592: if (mdao.isWriteEnable(document.getMenuId(), username)) {
593: Application application = FacesContext
594: .getCurrentInstance().getApplication();
595: RightsRecordsManager versionsManager = ((RightsRecordsManager) application
596: .createValueBinding(
597: "#{rightsRecordsManager}")
598: .getValue(FacesContext.getCurrentInstance()));
599: versionsManager.selectDocument(document);
600:
601: DocumentNavigation documentNavigation = ((DocumentNavigation) application
602: .createValueBinding("#{documentNavigation}")
603: .getValue(FacesContext.getCurrentInstance()));
604: documentNavigation
605: .setSelectedPanel(new PageContentBean(
606: "rights"));
607: } else {
608: Messages.addError(Messages
609: .getMessage("errors.noaccess"));
610: }
611: } catch (Exception ex) {
612: log.error(ex.getMessage(), ex);
613: Messages.addError(Messages.getMessage("errors.error"));
614: }
615: } else {
616: return "login";
617: }
618:
619: return null;
620: }
621:
622: /**
623: * Shows the articles for this document
624: */
625: public String articles() {
626: if (SessionManagement.isValid()) {
627: try {
628: Application application = FacesContext
629: .getCurrentInstance().getApplication();
630: ArticlesRecordsManager articlesManager = ((ArticlesRecordsManager) application
631: .createValueBinding("#{articlesRecordsManager}")
632: .getValue(FacesContext.getCurrentInstance()));
633: articlesManager.selectDocument(document);
634:
635: DocumentNavigation documentNavigation = ((DocumentNavigation) application
636: .createValueBinding("#{documentNavigation}")
637: .getValue(FacesContext.getCurrentInstance()));
638: documentNavigation
639: .setSelectedPanel(new PageContentBean(
640: "articles"));
641: } catch (Exception ex) {
642: log.error(ex.getMessage(), ex);
643: Messages.addError(Messages.getMessage("errors.error"));
644: }
645: } else {
646: return "login";
647: }
648:
649: return null;
650: }
651:
652: /**
653: * Shows the history of this document
654: */
655: public String history() {
656: if (SessionManagement.isValid()) {
657: Application application = FacesContext.getCurrentInstance()
658: .getApplication();
659: DocumentNavigation documentNavigation = ((DocumentNavigation) application
660: .createValueBinding("#{documentNavigation}")
661: .getValue(FacesContext.getCurrentInstance()));
662: documentNavigation.setSelectedPanel(new PageContentBean(
663: "history"));
664:
665: HistoryRecordsManager manager = ((HistoryRecordsManager) application
666: .createValueBinding("#{historyRecordsManager}")
667: .getValue(FacesContext.getCurrentInstance()));
668: manager.selectDocument(this .getDocument());
669: } else {
670: return "login";
671: }
672:
673: return null;
674: }
675:
676: public String info() {
677: // All goes as edit action
678: edit();
679:
680: // Now initialize the form
681: Application application = FacesContext.getCurrentInstance()
682: .getApplication();
683: DocumentEditForm docForm = ((DocumentEditForm) application
684: .createValueBinding("#{documentForm}").getValue(
685: FacesContext.getCurrentInstance()));
686: docForm.init(this );
687: docForm.setReadOnly(true);
688:
689: return null;
690: }
691:
692: public String sendAsEmail() {
693: // Show the proper panel
694: Application application = FacesContext.getCurrentInstance()
695: .getApplication();
696: DocumentNavigation documentNavigation = ((DocumentNavigation) application
697: .createValueBinding("#{documentNavigation}").getValue(
698: FacesContext.getCurrentInstance()));
699: documentNavigation
700: .setSelectedPanel(new PageContentBean("email"));
701:
702: // Now initialize the form
703: EMailForm emailForm = ((EMailForm) application
704: .createValueBinding("#{emailForm}").getValue(
705: FacesContext.getCurrentInstance()));
706: emailForm.reset();
707: emailForm.setSelectedDocument(getDocument());
708: emailForm.getAttachments().add(getDocument().getMenu());
709: emailForm.setAuthor(SessionManagement.getUser().getEmail());
710:
711: return null;
712: }
713:
714: public String sendAsTicket() {
715: // Show the proper panel
716: Application application = FacesContext.getCurrentInstance()
717: .getApplication();
718: DocumentNavigation documentNavigation = ((DocumentNavigation) application
719: .createValueBinding("#{documentNavigation}").getValue(
720: FacesContext.getCurrentInstance()));
721: documentNavigation
722: .setSelectedPanel(new PageContentBean("email"));
723:
724: // Now initialize the form
725: EMailForm emailForm = ((EMailForm) application
726: .createValueBinding("#{emailForm}").getValue(
727: FacesContext.getCurrentInstance()));
728: emailForm.reset();
729: emailForm.setSelectedDocument(getDocument());
730: emailForm.setAuthor(SessionManagement.getUser().getEmail());
731:
732: String username = SessionManagement.getUsername();
733: Date date = new Date();
734: String temp = DateFormat.getDateInstance().format(date)
735: + username;
736: String ticketid = CryptBean.cryptString(temp);
737: DownloadTicket ticket = new DownloadTicket();
738: ticket.setTicketId(ticketid);
739: ticket.setMenuId(getMenuId());
740: ticket.setUsername(username);
741:
742: DownloadTicketDAO ticketDao = (DownloadTicketDAO) Context
743: .getInstance().getBean(DownloadTicketDAO.class);
744: ticketDao.store(ticket);
745:
746: HttpServletRequest request = (HttpServletRequest) FacesContext
747: .getCurrentInstance().getExternalContext().getRequest();
748: request.getRequestURL();
749:
750: String address = "http://";
751: address += (request.getServerName() + ":");
752: address += request.getServerPort();
753: address += request.getContextPath();
754: address += ("/download-ticket?ticketId=" + ticketid);
755: emailForm.setText("URL: " + address);
756:
757: return null;
758: }
759: }
|