View Javadoc

1   /*
2    * This file is part of Domingo
3    * an Open Source Java-API to Lotus Notes/Domino
4    * hosted at http://domingo.sourceforge.net
5    *
6    * Copyright (c) 2003-2007 Beck et al. projects GmbH Munich, Germany (http://www.bea.de)
7    *
8    * This library is free software; you can redistribute it and/or
9    * modify it under the terms of the GNU Lesser General Public
10   * License as published by the Free Software Foundation; either
11   * version 2.1 of the License, or (at your option) any later version.
12   *
13   * This library is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   * Lesser General Public License for more details.
17   *
18   * You should have received a copy of the GNU Lesser General Public
19   * License along with this library; if not, write to the Free Software
20   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21   */
22  
23  package de.bea.domingo.http;
24  
25  import java.io.ByteArrayInputStream;
26  import java.io.IOException;
27  import java.util.ArrayList;
28  import java.util.Calendar;
29  import java.util.Iterator;
30  import java.util.List;
31  
32  import javax.xml.parsers.ParserConfigurationException;
33  import javax.xml.parsers.SAXParser;
34  
35  import org.apache.commons.httpclient.HttpStatus;
36  import org.xml.sax.Attributes;
37  import org.xml.sax.SAXException;
38  
39  import de.bea.domingo.DBase;
40  import de.bea.domingo.DBaseItem;
41  import de.bea.domingo.DDatabase;
42  import de.bea.domingo.DDocument;
43  import de.bea.domingo.DItem;
44  import de.bea.domingo.DNotesMonitor;
45  import de.bea.domingo.DNotesRuntimeException;
46  import de.bea.domingo.DView;
47  
48  /***
49   * Http implementation of a Domingo document.
50   *
51   * @author <a href=mailto:kriede@users.sourceforge.net>Kurt Riede</a>
52   */
53  public final class DocumentHttp extends BaseDocumentHttp implements DDocument {
54  
55      /*** Value for item <tt>tmpSendOptions</tt>: Indicates to only send when sending a document. */
56      private static final String SEND = "1";
57  
58      /*** Value for item <tt>tmpSendOptions</tt>: Indicates to also save when sending a document. */
59      private static final String SEND_AND_SAVE = "2";
60  
61      /*** Value for item <tt>tmpSendOptions</tt>: Indicates to also only save as draft save when sending a document. */
62      private static final String SEND_SAVE_AS_DRAFT = "3";
63  
64      /*** serial version ID for serialization. */
65      private static final long serialVersionUID = 1484836582323425207L;
66  
67      private String fUniversalId;
68  
69      private boolean fResponse;
70  
71      private boolean fEncryptOnSend;
72  
73      private boolean fSaveOnSend;
74  
75      private boolean fSignOnSend;
76  
77      private String fParentDocumentUNID;
78  
79      private boolean fNewNote;
80  
81      private boolean fSignOnSave;
82  
83      /***
84       * Private Constructor for this class.
85       *
86       * @param factory the controlling factory
87       * @param parent the parent object
88       * @param unid the universal ID of the document
89       * @param monitor the monitor that handles logging
90       * @see lotus.domino.Database
91       */
92      protected DocumentHttp(final NotesHttpFactory factory, final DBase parent, final String unid, final DNotesMonitor monitor) {
93          super(factory, parent, unid, monitor);
94          this.fUniversalId = unid;
95          if (unid != null && unid.length() > 0) {
96              readDocument();
97          }
98          fResponse = hasItem("$Ref");
99          fParentDocumentUNID = getItemValueString("$Ref");
100         fEncryptOnSend = "1".equals(getItemValueString("Encrypt"));
101         fSaveOnSend = "1".equals(getItemValueString("SaveOptions"));
102         fSignOnSend = "1".equals(getItemValueString("Sign"));
103         fNewNote = false;
104     }
105 
106     /***
107      * Private Constructor for this class.
108      *
109      * @param factory the controlling factory
110      * @param parent the parent object
111      * @param monitor the monitor that handles logging
112      * @see lotus.domino.Database
113      */
114     protected DocumentHttp(final NotesHttpFactory factory, final DBase parent, final DNotesMonitor monitor) {
115         super(factory, parent, monitor);
116         this.fUniversalId = "";
117         fNewNote = true;
118     }
119 
120     /***
121      * Factory method for instances of this class.
122      *
123      * @param theFactory the controlling factory
124      * @param theParent the session that produced the database
125      * @param unid the universal id of a Notes document
126      * @param monitor the monitor that handles logging
127      *
128      * @return Returns a DDatabase instance of type DatabaseProxy
129      */
130     static DDocument getInstance(final NotesHttpFactory theFactory, final DBase theParent, final String unid,
131             final DNotesMonitor monitor) {
132         return new DocumentHttp(theFactory, theParent, unid, monitor);
133     }
134 
135     /***
136      * Factory method for instances of this class.
137      *
138      * @param factory the controlling factory
139      * @param parent the session that produced the database
140      * @param monitor the monitor that handles logging
141      *
142      * @return Returns a DDatabase instance of type DatabaseProxy
143      */
144     static DDocument getInstance(final NotesHttpFactory factory, final DBase parent,
145             final DNotesMonitor monitor) {
146         return new DocumentHttp(factory, parent, monitor);
147     }
148 
149     private void readDocument() {
150         if (getDSession().isDomingoAvailable()) {
151             readDocumentByXML();
152         } else {
153             readDocumentByHtml();
154         }
155     }
156 
157     /***
158      * Reads a document in HTML format directly from the Http server.
159      */
160     private void readDocumentByHtml() {
161         BaseHttp parent = getParent();
162         String viewName;
163         if (parent instanceof DView) {
164             viewName = ((DView) parent).getName();
165             parent = parent.getParent();
166         } else {
167             viewName = "0";
168         }
169         if (!(parent instanceof DDatabase)) {
170             throw new NotesHttpRuntimeException("Unsupported parent: " + parent.getClass().getName());
171         }
172         String databaseName = ((DDatabase) parent).getFileName();
173         String url = databaseName + "/" + viewName + "/" + this.fUniversalId + "?EditDocument" + "?OpenDocument";
174         try {
175             final String bs = executeUrl(url);
176         } catch (IOException e) {
177             throw new NotesHttpRuntimeException(e);
178         }
179     }
180 
181     /***
182      * Reads a document in XML format from the Domingo database.
183      */
184     private void readDocumentByXML() {
185         try {
186             final String bs = execute("cmd=ReadDocument&unid=" + fUniversalId);
187             final SAXParser parser = getDSession().getFactory().getSAXParserFactory().newSAXParser();
188             final DocumentParser documentParser = new DocumentParser();
189             parser.parse(new ByteArrayInputStream(bs.getBytes()), documentParser);
190         } catch (IOException e) {
191             throw new NotesHttpRuntimeException(e);
192         } catch (ParserConfigurationException e) {
193             throw new NotesHttpRuntimeException(e);
194         } catch (SAXException e) {
195             throw new NotesHttpRuntimeException(e);
196         }
197     }
198 
199     /***
200      * {@inheritDoc}
201      *
202      * @see de.bea.domingo.DDocument#isNewNote()
203      */
204     public boolean isNewNote() {
205         return fNewNote;
206     }
207 
208     /***
209      * {@inheritDoc}
210      *
211      * @see de.bea.domingo.DDocument#getUniversalID()
212      */
213     public String getUniversalID() {
214         return fUniversalId;
215     }
216 
217     /***
218      * {@inheritDoc}
219      *
220      * @see de.bea.domingo.DDocument#getNoteID()
221      */
222     public String getNoteID() {
223         throw new UnsupportedOperationException("getNoteID()");
224     }
225 
226     /***
227      * {@inheritDoc}
228      * @throws IOException
229      *
230      * @see de.bea.domingo.DBaseDocument#save(boolean, boolean)
231      */
232     public boolean save(final boolean force, final boolean makeresponse) throws DNotesRuntimeException {
233         final String path = getParentDatabase().getFilePath();
234         final String args = "&sign=" + fSignOnSave;
235         final String object =  isNewNote() ? ((DItem) getFirstItem("Form")).getValueString() : getUniversalID();
236         final String command = isNewNote() ? "CreateDocument" : "SaveDocument";
237         final String pathInfo = path + "/" + object + "?" + command + args;
238         final DominoPostMethod method = getDSession().createPostMethod(pathInfo);
239         final Iterator itemIterator = getItems();
240         while (itemIterator.hasNext()) {
241             final DBaseItem item = (DBaseItem) itemIterator.next();
242             if (item instanceof DItem) {
243                 final Iterator valueIterator = ((DItem) item).getValues().iterator();
244                 while (valueIterator.hasNext()) {
245                     addParameter(method, item.getName(), valueIterator.next());
246                 }
247             }
248         }
249         try {
250             final int statusCode = getDSession().executeMethod(method);
251             if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_MOVED_TEMPORARILY) {
252                 getMonitor().error("Http request failed: " + method.getStatusLine());
253             }
254             // TODO we must also check the content of the response for errors when saving documents
255             return statusCode == HttpStatus.SC_OK;
256         } catch (IOException e) {
257             getMonitor().error(e.getLocalizedMessage(), e);
258             throw new NotesHttpRuntimeException(e.getLocalizedMessage(), e);
259         } finally {
260             method.releaseConnection();
261         }
262     }
263 
264     private void addParameter(final DominoPostMethod method, final String name, final Object value) {
265         if (value instanceof Calendar) {
266             method.addParameter(name, value.toString());
267         } else if (value instanceof Number) {
268             method.addParameter(name, value.toString());
269         } else if (value instanceof String) {
270             method.addParameter(name, value.toString());
271         }
272     }
273 
274     /***
275      * {@inheritDoc}
276      *
277      * @see de.bea.domingo.DDocument#send(java.lang.String)
278      */
279     public void send(final String recipient) {
280         final List list = new ArrayList();
281         list.add(recipient);
282         send(list);
283     }
284 
285     /***
286      * {@inheritDoc}
287      *
288      * @see de.bea.domingo.DDocument#send(java.util.List)
289      */
290     public void send(final List recipients) {
291         // prepare document for post as mail
292         replaceItemValue("WebSubject", getItemValue("Subject"));
293         replaceItemValue("tmpSendOptions", fSaveOnSend ? SEND_AND_SAVE : SEND);
294         replaceItemValue("__Click", getItemValue("0"));
295         // TODO replaceItemValue("%%ModDate", "C1257276006A90C8");
296         // Post the document
297         final String path = getParentDatabase().getFilePath();
298         final String args = "&encrypt=" + fEncryptOnSend + "&save=" + fSaveOnSend + "&sign=" + fSignOnSend;
299         try {
300             // TODO check document.send()
301             String result = execute(path, args);
302 //            bs = execute("file=" + path + "&cmd=EditDocument&Seq=1&unid=" + fUniversalId + args);
303 //            bs = this.postDXL("file=" + path + "&cmd=SendDocument&unid=" + universalId + args, this);
304             getMonitor().debug(result);
305             // TODO if is new doc: get NoteId from response and reload document to
306             // get the universalId
307         } catch (IOException e) {
308             throw new NotesHttpRuntimeException("Cannot save document: " + e.getMessage(), e);
309         }
310     }
311 
312     /***
313      * {@inheritDoc}
314      *
315      * @see de.bea.domingo.DDocument#copyToDatabase(de.bea.domingo.DDatabase)
316      */
317     public DDocument copyToDatabase(final DDatabase database) {
318         throw new UnsupportedOperationException("copyToDatabase()");
319     }
320 
321     /***
322      * {@inheritDoc}
323      *
324      * @see de.bea.domingo.DDocument#isResponse()
325      */
326     public boolean isResponse() {
327         return fResponse;
328     }
329 
330     /***
331      * {@inheritDoc}
332      *
333      * @see de.bea.domingo.DDocument#getParentDocumentUNID()
334      */
335     public String getParentDocumentUNID() {
336         return fParentDocumentUNID;
337     }
338 
339     /***
340      * {@inheritDoc}
341      *
342      * @see de.bea.domingo.DDocument#getParentDocument()
343      */
344     public DDocument getParentDocument() {
345         return getInstance(getFactory(), getParent(), getParentDocumentUNID(), getMonitor());
346     }
347 
348     /***
349      * {@inheritDoc}
350      *
351      * @see de.bea.domingo.DDocument#makeResponse(de.bea.domingo.DDocument)
352      */
353     public void makeResponse(final DDocument doc) {
354         throw new UnsupportedOperationException("makeResponse()");
355     }
356 
357     /***
358      * {@inheritDoc}
359      *
360      * @see de.bea.domingo.DDocument#getResponses()
361      */
362     public Iterator getResponses() {
363         throw new UnsupportedOperationException("getResponses()");
364     }
365 
366     /***
367      * {@inheritDoc}
368      *
369      * @see de.bea.domingo.DDocument#setSaveMessageOnSend(boolean)
370      */
371     public void setSaveMessageOnSend(final boolean flag) {
372         fSaveOnSend = flag;
373     }
374 
375     /***
376      * {@inheritDoc}
377      *
378      * @see de.bea.domingo.DDocument#setEncryptOnSend(boolean)
379      */
380     public void setEncryptOnSend(final boolean flag) {
381         fEncryptOnSend = flag;
382     }
383 
384     /***
385      * {@inheritDoc}
386      *
387      * @see de.bea.domingo.DDocument#setSignOnSend(boolean)
388      */
389     public void setSignOnSend(final boolean flag) {
390         fSignOnSend = flag;
391     }
392 
393     /***
394      * {@inheritDoc}
395      *
396      * @see de.bea.domingo.DDocument#sign()
397      */
398     public void sign() {
399         fSignOnSave = true;
400     }
401 
402     /***
403      * {@inheritDoc}
404      *
405      * @see de.bea.domingo.DDocument#replaceHTML(java.lang.String,
406      *      java.lang.String)
407      */
408     public void replaceHTML(final String name, final String value) {
409         throw new UnsupportedOperationException("replaceHTML()");
410     }
411 
412     /***
413      * {@inheritDoc}
414      *
415      * @see de.bea.domingo.DDocument#getFTSearchScore()
416      */
417     public int getFTSearchScore() {
418         throw new UnsupportedOperationException("getFTSearchScope()");
419     }
420 
421     /***
422      * SAX parser for documents.
423      */
424     private class DocumentParser extends BaseHandler {
425 
426         private String fName;
427 
428         private boolean fNames;
429 
430         private boolean fReaders;
431 
432         private boolean fAuthors;
433 
434         public void startElement(final String namespaceURI, final String localName, final String qName, final Attributes atts)
435                 throws SAXException {
436             if ("item".equals(qName)) {
437                 fName = atts.getValue("name");
438                 String n = atts.getValue("names");
439                 fNames = n != null && n.equals("true");
440                 String r = atts.getValue("readers");
441                 fReaders = r != null && r.equals("true");
442                 String a = atts.getValue("authors");
443                 fAuthors = a != null && a.equals("true");
444                 reset();
445             } else {
446                 super.startElement(namespaceURI, localName, qName, atts);
447             }
448         }
449 
450         public void endElement(final String uri, final String localName, final String qName) throws SAXException {
451             if ("item".equals(qName)) {
452                 final DItem item = replaceItemValue(fName, getValues());
453                 item.setNames(fNames);
454                 item.setReaders(fReaders);
455                 item.setAuthors(fAuthors);
456             } else {
457                 super.endElement(uri, localName, qName);
458             }
459         }
460     }
461 
462     /***
463      * {@inheritDoc}
464      *
465      * @see de.bea.domingo.DDocument#getParentView()
466      */
467     public DView getParentView() {
468         throw new UnsupportedOperationException("not supported in Http Document");
469     }
470 
471     /***
472      * {@inheritDoc}
473      *
474      * @see de.bea.domingo.DDocument#getFolderReferences()
475      */
476     public List getFolderReferences() {
477         throw new UnsupportedOperationException("not supported in Http Document");
478     }
479 
480     /***
481      * {@inheritDoc}
482      *
483      * @see de.bea.domingo.DDocument#putInFolder(java.lang.String)
484      */
485     public void putInFolder(final String s) {
486         throw new UnsupportedOperationException("not supported in Http Document");
487     }
488 
489     /***
490      * {@inheritDoc}
491      *
492      * @see de.bea.domingo.DDocument#putInFolder(java.lang.String, boolean)
493      */
494     public void putInFolder(final String s, final boolean flag) {
495         throw new UnsupportedOperationException("not supported in Http Document");
496     }
497 
498     /***
499      * {@inheritDoc}
500      *
501      * @see de.bea.domingo.DDocument#removeFromFolder(java.lang.String)
502      */
503     public void removeFromFolder(final String s) {
504         throw new UnsupportedOperationException("not supported in Http Document");
505     }
506 
507     /***
508      * {@inheritDoc}
509      *
510      * @see de.bea.domingo.DDocument#getURL()
511      */
512     public String getURL() {
513         throw new UnsupportedOperationException("not supported in Http Document");
514     }
515 
516     /***
517      * {@inheritDoc}
518      *
519      * @see de.bea.domingo.DDocument#getNotesURL()
520      */
521     public String getNotesURL() {
522         throw new UnsupportedOperationException("not supported in Http Document");
523     }
524 
525     /***
526      * {@inheritDoc}
527      *
528      * @see de.bea.domingo.DDocument#getHttpURL()
529      */
530     public String getHttpURL() {
531         throw new UnsupportedOperationException("not supported in Http Document");
532     }
533 }