View Javadoc

1   package org.varienaja.comments;
2   
3   import java.io.File;
4   import java.io.FileNotFoundException;
5   import java.io.FileReader;
6   import java.io.IOException;
7   import java.io.PrintWriter;
8   import java.util.Set;
9   import java.util.TreeSet;
10  
11  import javax.xml.transform.OutputKeys;
12  import javax.xml.transform.Transformer;
13  import javax.xml.transform.TransformerConfigurationException;
14  import javax.xml.transform.sax.SAXTransformerFactory;
15  import javax.xml.transform.sax.TransformerHandler;
16  import javax.xml.transform.stream.StreamResult;
17  
18  import org.apache.log4j.Logger;
19  import org.musicontroller.service.FileUtils;
20  import org.varienaja.util.DateTools;
21  import org.xml.sax.Attributes;
22  import org.xml.sax.InputSource;
23  import org.xml.sax.SAXException;
24  import org.xml.sax.XMLReader;
25  import org.xml.sax.helpers.AttributesImpl;
26  import org.xml.sax.helpers.DefaultHandler;
27  import org.xml.sax.helpers.XMLReaderFactory;
28  
29  /**
30   * Class for handling SAX-events while reading Comments from XML.
31   * @author Varienaja
32   * @version $Id: CommentDAO.java,v 1.1 2010/03/16 18:55:42 varienaja Exp $
33   */
34  class CommentHandler extends DefaultHandler {
35  	private Set<Comment> _comments;
36  	private Comment _comment;
37  	private CommentElement _commentElement;
38  	private StringBuilder _elementText;
39  	private boolean _acceptCharacters;
40  	
41  	/**
42  	 * Create the SAX-eventhandler. Pass the (non-null) Set of Reviews here, so
43  	 * the handler can add the reviews to it.
44  	 * @param reviews
45  	 */
46  	public CommentHandler(Set<Comment> reviews) {
47  		_comments = reviews;
48  		_acceptCharacters = false;
49  	}
50  	
51  	/*
52  	 * (non-Javadoc)
53  	 * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
54  	 */
55  	public void startElement(String uri, String name, String qName, Attributes atts) {
56  		if (CommentDAO.REVIEW.equals(qName)) {
57  			_comment = new Comment(
58  					atts.getValue("source"),
59  					atts.getValue("title"),
60  					DateTools.parseDate(atts.getValue("date"), CommentDAO.DATEPATTERN)
61  					);
62  		}
63  		if (CommentDAO.REVIEWELEMENT.equals(qName)) {
64  			_commentElement = new CommentElement();
65  			_commentElement.setId(Long.parseLong(atts.getValue("id")));
66  			_commentElement.setType(atts.getValue("elttype").charAt(0));
67  			_elementText = new StringBuilder();
68  			_acceptCharacters = true;
69  		}
70  	}
71  	
72  	/*
73  	 * (non-Javadoc)
74  	 * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
75  	 */
76  	public void endElement(String uri, String name, String qName) {
77  		if (CommentDAO.REVIEW.equals(qName)) {
78  			_comments.add(_comment);
79  		}
80  		if (CommentDAO.REVIEWELEMENT.equals(qName)) {
81  			_acceptCharacters = false;
82  			_commentElement.setText(_elementText.toString());
83  			_comment.addElement(_commentElement);
84  		}
85  	}
86  	
87  	/*
88  	 * (non-Javadoc)
89  	 * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
90  	 */
91  	public void characters(char ch[], int start, int length) {
92  		if (_acceptCharacters) {
93  			_elementText.append(ch, start, length);
94  		}
95  	}
96  	
97  }
98  
99  
100 /**
101  * Class that persists and reads Reviews from persistent storage.
102  * @author Varienaja
103  */
104 public final class CommentDAO {
105 	private static final Logger log = Logger.getLogger(CommentDAO.class);
106 	protected final static String REVIEWS = "reviews";
107 	protected final static String REVIEW = "review";
108 	protected final static String REVIEWELEMENTS = "reviewelements";
109 	protected final static String REVIEWELEMENT = "reviewelement";
110 	protected final static String DATEPATTERN = "dd-MM-yyyy";
111 	
112 	
113 	/**
114      * Stores the reviews of an item on disk.
115      * @param fileprefix The prefix to use for the file on local storage.
116      * @param id The id to add to the fileprefix.
117      * @param comments The Reviews to store. 
118      * @return Whether the operation succeeded or not.
119      */
120 	public static synchronized boolean saveCommentsToCache(String fileprefix, long id, Set<Comment> comments) {
121 		File storage = getStorage(fileprefix, id);
122 		if (comments.size()==0) {
123 			return (storage.exists()) ? storage.delete() : true;
124 		} else {
125 			try {
126 				PrintWriter out = new PrintWriter(storage);
127 				StreamResult streamResult = new StreamResult(out);
128 				SAXTransformerFactory tf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
129 				TransformerHandler hd = tf.newTransformerHandler();
130 				Transformer t = hd.getTransformer();
131 				t.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
132 				//t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "a.dtd");
133 				t.setOutputProperty(OutputKeys.INDENT, "yes");
134 				hd.setResult(streamResult);
135 				hd.startDocument();
136 				
137 				AttributesImpl atts = new AttributesImpl();
138 				atts.addAttribute("", "", "playlistid", "CDATA", Long.toString(id));
139 				hd.startElement("", "", REVIEWS, atts); //reviews-tag
140 				for (Comment review : comments) {
141 					atts.clear();
142 					atts.addAttribute("", "", "title", "CDATA", review.getTitle());
143 					atts.addAttribute("", "", "source", "CDATA", review.getSource());
144 					atts.addAttribute("", "", "date", "CDATA", DateTools.formatDate(review.getDate(),DATEPATTERN));
145 					hd.startElement("", "", REVIEW, atts);
146 
147 					atts.clear();
148 					hd.startElement("", "", REVIEWELEMENTS, atts);
149 					for (CommentElement elt : review.getElements()) {
150 						atts.clear();
151 						atts.addAttribute("", "", "elttype", "CDATA", elt.getType());
152 						atts.addAttribute("", "", "id", "CDATA", Long.toString(elt.getId()));
153 						hd.startElement("", "", REVIEWELEMENT, atts);
154 						hd.characters(elt.getText().toCharArray(), 0, elt.getText().length());
155 						hd.endElement("", "", REVIEWELEMENT);
156 					}
157 					hd.endElement("", "", REVIEWELEMENTS);
158 					hd.endElement("", "", REVIEW);
159 				}
160 				hd.endElement("", "", REVIEWS);
161 				hd.endDocument();
162 				out.close();
163 				return true;
164 			} catch (FileNotFoundException e) {
165 				log.error("Error opening reviewstorage: "+e);
166 			} catch (TransformerConfigurationException e) {
167 				e.printStackTrace();
168 			} catch (SAXException e) {
169 				e.printStackTrace();
170 			}
171 			return false;
172 		}
173     }
174     
175 	
176 	/**
177 	 * Loads Reviews of an item from the disk. Returns null if there were no cached
178 	 * Reviews of this item.
179      * @param fileprefix The prefix to use for the file on local storage.
180 	 * @id The id of the item.
181 	 * @return A List of Reviews. Returns <code>null</code> if the review storage 
182 	 * directory does not exist.
183 	 */
184 	public static Set<Comment> getCommentsFromCache(String fileprefix, long id) {
185 		File storage = getStorage(fileprefix, id);
186 		if (storage.exists()) {
187 			FileReader reader = null;
188 			try {
189 				Set<Comment> comments = new TreeSet<Comment>();
190 				XMLReader xr = XMLReaderFactory.createXMLReader();
191 				CommentHandler handler = new CommentHandler(comments);
192 				xr.setContentHandler(handler);
193 				xr.setErrorHandler(handler);
194 				reader = new FileReader(storage);
195 				xr.parse(new InputSource(reader));
196 				log.debug("Read "+comments.size()+" comments from persistent storage for "+fileprefix+"-id: "+id);
197 				return comments;
198 			} catch (SAXException e) {
199 				log.error("Error parsing Review-XML: "+e);
200 			} catch (FileNotFoundException e) {
201 				log.error("Review-XML file not found: "+e);
202 			} catch (IOException e) {
203 				log.error("I/O Exception reading Review-XML: "+e);
204 			} finally {
205 				if (reader!=null) {
206 					try {
207 						reader.close();
208 					} catch (IOException e) {
209 						log.error("Error closing filereader." + e);
210 					}
211 				}
212 			}
213 		}
214 		return null;
215 	}
216 
217 	
218 	/**
219 	 * Returns the file where we store the Review-data for this item.
220 	 * @param id The item-id
221 	 * @return The File where the Reviews for the item are stored.
222 	 */
223 	private static File getStorage(String fileprefix, long id) {
224 		File storage = new File(FileUtils.getReviewdir()+File.separator+fileprefix+id+".xml");
225 		return storage;
226 	}
227 
228 }