001: /**
002: * Copyright (c) 2003-2007, David A. Czarnecki
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are met:
007: *
008: * Redistributions of source code must retain the above copyright notice, this list of conditions and the
009: * following disclaimer.
010: * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
011: * following disclaimer in the documentation and/or other materials provided with the distribution.
012: * Neither the name of "David A. Czarnecki" and "blojsom" nor the names of its contributors may be used to
013: * endorse or promote products derived from this software without specific prior written permission.
014: * Products derived from this software may not be called "blojsom", nor may "blojsom" appear in their name,
015: * without prior written permission of David A. Czarnecki.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
018: * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
019: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
021: * EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
022: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
025: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
026: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
027: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
028: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
029: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030: */package org.blojsom.plugin.delicious;
031:
032: import del.icio.us.Delicious;
033: import del.icio.us.DeliciousUtils;
034: import org.apache.commons.logging.Log;
035: import org.apache.commons.logging.LogFactory;
036: import org.blojsom.blog.Blog;
037: import org.blojsom.blog.Entry;
038: import org.blojsom.event.EventBroadcaster;
039: import org.blojsom.fetcher.Fetcher;
040: import org.blojsom.fetcher.FetcherException;
041: import org.blojsom.plugin.PluginException;
042: import org.blojsom.plugin.admin.event.EntryAddedEvent;
043: import org.blojsom.plugin.velocity.StandaloneVelocityPlugin;
044: import org.blojsom.util.BlojsomMetaDataConstants;
045: import org.blojsom.util.BlojsomUtils;
046:
047: import javax.servlet.ServletConfig;
048: import javax.servlet.http.HttpServletRequest;
049: import javax.servlet.http.HttpServletResponse;
050: import java.text.MessageFormat;
051: import java.util.*;
052:
053: /**
054: * Plugin to post links from your <a href="http://del.icio.us">del.icio.us</a> account to your blog.
055: *
056: * @author David Czarnecki
057: * @version $Id: DailyPostingPlugin.java,v 1.3 2007/01/17 02:35:06 czarneckid Exp $
058: * @since blojsom 3.0
059: */
060: public class DailyPostingPlugin extends StandaloneVelocityPlugin {
061:
062: private Log _logger = LogFactory.getLog(DailyPostingPlugin.class);
063:
064: // Plugin configuration parameters
065: private static final String DAILY_POSTING_POLL_TIME_IP = "daily-posting-poll-time";
066: private static final int DAILY_POSTING_POLL_TIME_DEFAULT = (1000 * 60 * 60);
067: private int _pollTime = DAILY_POSTING_POLL_TIME_DEFAULT;
068:
069: // Template
070: private static final String DAILY_POSTING_TEMPLATE = "org/blojsom/plugin/delicious/daily-posting-template.vm";
071:
072: // Context variables
073: private static final String DAILY_POSTING_USERNAME = "DAILY_POSTING_USERNAME";
074: private static final String DAILY_POSTING_POSTS = "DAILY_POSTING_POSTS";
075:
076: // Individual configuration parameters
077: private static final String DAILY_POSTING_USERNAME_IP = "daily-posting-username";
078: private static final String DAILY_POSTING_PASSWORD_IP = "daily-posting-password";
079: private static final String DAILY_POSTING_CATEGORY_IP = "daily-posting-category";
080: private static final String DAILY_POSTING_HOUR_IP = "daily-posting-hour";
081: private static final String DAILY_POSTING_TITLE_IP = "daily-posting-title";
082: private static final String DAILY_POSTING_AUTHOR_IP = "daily-posting-author";
083: private static final String DAILY_POSTING_TITLE_DEFAULT = "del.icio.us links for {0}";
084:
085: private boolean _finished = false;
086: private DeliciousChecker _checker;
087:
088: private String _proxyHost = null;
089: private String _proxyPort = null;
090:
091: private Fetcher _fetcher;
092: private ServletConfig _servletConfig;
093: private EventBroadcaster _eventBroadcaster;
094:
095: /**
096: * Create a new instance of the daily posting plugin
097: */
098: public DailyPostingPlugin() {
099: }
100:
101: /**
102: * Set the {@link Fetcher}
103: *
104: * @param fetcher {@link Fetcher}
105: */
106: public void setFetcher(Fetcher fetcher) {
107: _fetcher = fetcher;
108: }
109:
110: /**
111: * Set the {@link ServletConfig} for the fetcher to grab initialization parameters
112: *
113: * @param servletConfig {@link ServletConfig}
114: */
115: public void setServletConfig(ServletConfig servletConfig) {
116: _servletConfig = servletConfig;
117: }
118:
119: /**
120: * Set the {@link EventBroadcaster}
121: *
122: * @param eventBroadcaster {@link EventBroadcaster}
123: */
124: public void setEventBroadcaster(EventBroadcaster eventBroadcaster) {
125: _eventBroadcaster = eventBroadcaster;
126: }
127:
128: /**
129: * Initialize this plugin. This method only called when the plugin is instantiated.
130: *
131: * @throws org.blojsom.plugin.PluginException
132: * If there is an error initializing the plugin
133: */
134: public void init() throws PluginException {
135: super .init();
136:
137: String pollTime = _servletConfig
138: .getInitParameter(DAILY_POSTING_POLL_TIME_IP);
139: if (BlojsomUtils.checkNullOrBlank(pollTime)) {
140: _pollTime = DAILY_POSTING_POLL_TIME_DEFAULT;
141: } else {
142: try {
143: _pollTime = Integer.parseInt(pollTime);
144: if (_pollTime < DAILY_POSTING_POLL_TIME_DEFAULT) {
145: _pollTime = DAILY_POSTING_POLL_TIME_DEFAULT;
146: }
147: } catch (NumberFormatException e) {
148: _pollTime = DAILY_POSTING_POLL_TIME_DEFAULT;
149: }
150: }
151:
152: try {
153: _proxyHost = System.getProperty("http.proxyHost");
154: _proxyPort = System.getProperty("http.proxyPort");
155: } catch (Exception e) {
156: _logger.error(e);
157: }
158:
159: _checker = new DeliciousChecker();
160: _checker.setDaemon(true);
161: _checker.start();
162: }
163:
164: /**
165: * Process the blog entries
166: *
167: * @param httpServletRequest Request
168: * @param httpServletResponse Response
169: * @param blog {@link Blog} instance
170: * @param context Context
171: * @param entries Blog entries retrieved for the particular request
172: * @return Modified set of blog entries
173: * @throws PluginException If there is an error processing the blog entries
174: */
175: public Entry[] process(HttpServletRequest httpServletRequest,
176: HttpServletResponse httpServletResponse, Blog blog,
177: Map context, Entry[] entries) throws PluginException {
178: return entries;
179: }
180:
181: /**
182: * Perform any cleanup for the plugin. Called after {@link #process}.
183: *
184: * @throws org.blojsom.plugin.PluginException
185: * If there is an error performing cleanup for this plugin
186: */
187: public void cleanup() throws PluginException {
188: }
189:
190: /**
191: * Called when BlojsomServlet is taken out of service
192: *
193: * @throws org.blojsom.plugin.PluginException
194: * If there is an error in finalizing this plugin
195: */
196: public void destroy() throws PluginException {
197: _finished = true;
198: }
199:
200: /**
201: * Checker thread for posting to del.icio.us
202: */
203: private class DeliciousChecker extends Thread {
204:
205: /**
206: * Allocates a new <code>Thread</code> object. This constructor has
207: * the same effect as <code>Thread(null, null,</code>
208: * <i>gname</i><code>)</code>, where <b><i>gname</i></b> is
209: * a newly generated name. Automatically generated names are of the
210: * form <code>"Thread-"+</code><i>n</i>, where <i>n</i> is an integer.
211: *
212: * @see Thread#Thread(ThreadGroup,
213: * Runnable, String)
214: */
215: public DeliciousChecker() {
216: super ();
217: }
218:
219: /**
220: * If this thread was constructed using a separate
221: * <code>Runnable</code> run object, then that
222: * <code>Runnable</code> object's <code>run</code> method is called;
223: * otherwise, this method does nothing and returns.
224: * <p/>
225: * Subclasses of <code>Thread</code> should override this method.
226: *
227: * @see Thread#start()
228: * @see Thread#stop()
229: * @see Thread#Thread(ThreadGroup,
230: * Runnable, String)
231: * @see Runnable#run()
232: */
233: public void run() {
234: try {
235: while (!_finished) {
236: String[] blogIDs = _fetcher.loadBlogIDs();
237:
238: Blog blog;
239: String blogID;
240:
241: for (int i = 0; i < blogIDs.length; i++) {
242: blogID = blogIDs[i];
243:
244: try {
245: blog = _fetcher.loadBlog(blogID);
246:
247: String postingCategory = blog
248: .getProperty(DAILY_POSTING_CATEGORY_IP);
249: String deliciousUsername = blog
250: .getProperty(DAILY_POSTING_USERNAME_IP);
251: String deliciousPassword = blog
252: .getProperty(DAILY_POSTING_PASSWORD_IP);
253: String postingHour = blog
254: .getProperty(DAILY_POSTING_HOUR_IP);
255: String postTitle = blog
256: .getProperty(DAILY_POSTING_TITLE_IP);
257: String postingAuthor = blog
258: .getProperty(DAILY_POSTING_AUTHOR_IP);
259:
260: if (BlojsomUtils
261: .checkNullOrBlank(postTitle)) {
262: postTitle = DAILY_POSTING_TITLE_DEFAULT;
263: }
264:
265: if (BlojsomUtils
266: .checkNullOrBlank(postingCategory)
267: || BlojsomUtils
268: .checkNullOrBlank(deliciousPassword)
269: || BlojsomUtils
270: .checkNullOrBlank(deliciousUsername)
271: || BlojsomUtils
272: .checkNullOrBlank(postingHour)) {
273: } else {
274: Date now = new Date();
275: Calendar calendar = Calendar
276: .getInstance();
277: calendar.setTime(now);
278: int currentHour = calendar
279: .get(Calendar.HOUR_OF_DAY);
280:
281: try {
282: int hourToPost = Integer
283: .parseInt(postingHour);
284: if (hourToPost == currentHour) {
285: Delicious delicious = new Delicious(
286: deliciousUsername,
287: deliciousPassword);
288: if (_proxyHost != null
289: && _proxyPort != null) {
290: delicious
291: .setProxyConfiguration(
292: _proxyHost,
293: Integer
294: .parseInt(_proxyPort));
295: }
296:
297: List posts = delicious
298: .getPostsForDate(null,
299: now);
300: if (posts.size() > 0) {
301: HashMap deliciousContext = new HashMap();
302: deliciousContext
303: .put(
304: DAILY_POSTING_USERNAME,
305: deliciousUsername);
306: deliciousContext
307: .put(
308: DAILY_POSTING_POSTS,
309: posts);
310:
311: String renderedLinkTemplate = mergeTemplate(
312: DAILY_POSTING_TEMPLATE,
313: blog,
314: deliciousContext);
315:
316: // Create the blog entry
317: String nowAsString = DeliciousUtils
318: .getDeliciousDate(now);
319: postingCategory = BlojsomUtils
320: .normalize(postingCategory);
321:
322: Entry entry;
323: entry = _fetcher.newEntry();
324:
325: String title = MessageFormat
326: .format(
327: postTitle,
328: new Object[] {
329: nowAsString,
330: deliciousUsername });
331: entry.setBlogId(blog
332: .getId());
333: entry.setTitle(title);
334: entry
335: .setDescription(renderedLinkTemplate);
336: entry.setDate(new Date());
337: entry
338: .setStatus(BlojsomMetaDataConstants.NEW_STATUS);
339: entry
340: .setBlogCategoryId(Integer
341: .valueOf(postingCategory));
342: try {
343: if (_fetcher.loadUser(
344: blog,
345: postingAuthor) != null) {
346: entry
347: .setAuthor(postingAuthor);
348: }
349: } catch (FetcherException e) {
350: }
351:
352: _fetcher.saveEntry(blog,
353: entry);
354:
355: _eventBroadcaster
356: .broadcastEvent(new EntryAddedEvent(
357: this ,
358: new Date(),
359: entry, blog));
360: if (_logger
361: .isDebugEnabled()) {
362: _logger
363: .debug("Posted del.icio.us links for: "
364: + blog
365: .getBlogId()
366: + " using: "
367: + deliciousUsername);
368: }
369: }
370: }
371: } catch (NumberFormatException e) {
372: }
373: }
374: } catch (FetcherException e) {
375: if (_logger.isErrorEnabled()) {
376: _logger.error(e);
377: }
378: }
379: }
380:
381: sleep(_pollTime);
382: }
383: } catch (InterruptedException e) {
384: if (_logger.isErrorEnabled()) {
385: _logger.error(e);
386: }
387: } catch (FetcherException e) {
388: if (_logger.isErrorEnabled()) {
389: _logger.error(e);
390: }
391: }
392: }
393: }
394: }
|