| 1 31 package org.blojsom.plugin.common; 32 33 import org.apache.commons.logging.Log; 34 import org.apache.commons.logging.LogFactory; 35 import org.blojsom.blog.Entry; 36 import org.blojsom.blog.Blog; 37 import org.blojsom.event.Event; 38 import org.blojsom.event.EventBroadcaster; 39 import org.blojsom.event.Listener; 40 import org.blojsom.plugin.Plugin; 41 import org.blojsom.plugin.PluginException; 42 import org.blojsom.plugin.admin.event.ProcessEntryEvent; 43 import org.blojsom.util.BlojsomUtils; 44 import org.blojsom.util.BlojsomConstants; 45 46 import javax.activation.MimetypesFileTypeMap ; 47 import javax.servlet.http.HttpServletRequest ; 48 import javax.servlet.http.HttpServletResponse ; 49 import javax.servlet.ServletConfig ; 50 import javax.servlet.ServletContext ; 51 import java.io.File ; 52 import java.net.HttpURLConnection ; 53 import java.net.URL ; 54 import java.text.MessageFormat ; 55 import java.util.HashMap ; 56 import java.util.Map ; 57 import java.util.TreeMap ; 58 import java.util.Properties ; 59 60 67 public class RSSEnclosurePlugin implements Plugin, Listener { 68 69 private Log _logger = LogFactory.getLog(RSSEnclosurePlugin.class); 70 71 private static final String RSS_ENCLOSURE_TEMPLATE = "org/blojsom/plugin/common/templates/admin-rss-enclosure-attachment.vm"; 72 private static final String RSS_ENCLOSURE_ATTACHMENT = "RSS_ENCLOSURE_ATTACHMENT"; 73 private static final String RSS_ENCLOSURE_URL_ITEM = "RSS_ENCLOSURE_URL_ITEM"; 74 private static final String RSS_ENCLOSURE_LENGTH_ITEM = "RSS_ENCLOSURE_LENGTH_ITEM"; 75 private static final String RSS_ENCLOSURE_TYPE_ITEM = "RSS_ENCLOSURE_TYPE_ITEM"; 76 private static final String RSS_ENCLOSURE_LINK_TEMPLATE = "<enclosure url=\"{0}\" length=\"{1}\" type=\"{2}\" />"; 77 78 protected static final String MIME_TYPE_XMPEGURL = "audio/x-mpegurl m3u"; 79 protected static final String MIME_TYPE_XMPEG = "audio/x-mpeg mp1 mp2 mp3 mpa mpega"; 80 81 public static final String DEFAULT_MIME_TYPE = "application/octet-stream"; 82 public static final String METADATA_RSS_ENCLOSURE = "rss-enclosure"; 83 public static final String METADATA_ESS_ENCLOSURE_OBJECT = "rss-enclosure-object"; 84 85 public static final String RSS_ENCLOSURE_URL = "rss-enclosure-url"; 86 public static final String RSS_ENCLOSURE_LENGTH = "rss-enclosure-length"; 87 public static final String RSS_ENCLOSURE_TYPE = "rss-enclosure-type"; 88 89 protected EventBroadcaster _eventBroadcaster; 90 protected ServletConfig _servletConfig; 91 protected Properties _blojsomProperties; 92 93 protected String _resourcesDirectory; 94 95 98 public RSSEnclosurePlugin() { 99 } 100 101 106 public void setBlojsomProperties(Properties blojsomProperties) { 107 _blojsomProperties = blojsomProperties; 108 } 109 110 115 public void setServletConfig(ServletConfig servletConfig) { 116 _servletConfig = servletConfig; 117 } 118 119 124 public void setEventBroadcaster(EventBroadcaster eventBroadcaster) { 125 _eventBroadcaster = eventBroadcaster; 126 } 127 128 135 public void init() throws PluginException { 136 _resourcesDirectory = _blojsomProperties.getProperty(BlojsomConstants.RESOURCES_DIRECTORY_IP, BlojsomConstants.DEFAULT_RESOURCES_DIRECTORY); 137 _eventBroadcaster.addListener(this); 138 139 _logger.debug("Initialized RSS enclosures plugin"); 140 } 141 142 147 protected void addAdditionalMimeTypes(MimetypesFileTypeMap mimeTypes) { 148 mimeTypes.addMimeTypes(MIME_TYPE_XMPEGURL); 149 mimeTypes.addMimeTypes(MIME_TYPE_XMPEG); 150 } 151 152 163 public Entry[] process(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Blog blog, Map context, Entry[] entries) throws PluginException { 164 ServletContext servletContext = _servletConfig.getServletContext(); 165 166 for (int i = 0; i < entries.length; i++) { 167 Entry entry = entries[i]; 168 if (BlojsomUtils.checkMapForKey(entry.getMetaData(), RSS_ENCLOSURE_URL) && BlojsomUtils.checkMapForKey(entry.getMetaData(), RSS_ENCLOSURE_LENGTH) && BlojsomUtils.checkMapForKey(entry.getMetaData(), RSS_ENCLOSURE_TYPE)) 169 { 170 String rssEnclosureURL = (String ) entry.getMetaData().get(RSS_ENCLOSURE_URL); 171 rssEnclosureURL = BlojsomUtils.escapeBrackets(rssEnclosureURL); 172 173 long rssEnclosureLength = -1; 174 try { 175 rssEnclosureLength = Long.parseLong((String ) entry.getMetaData().get(RSS_ENCLOSURE_LENGTH)); 176 } catch (NumberFormatException e) { 177 } 178 String rssEnclosureType = (String ) entry.getMetaData().get(RSS_ENCLOSURE_TYPE); 179 180 String rssEnclosure = MessageFormat.format(RSS_ENCLOSURE_LINK_TEMPLATE, new Object []{rssEnclosureURL, Long.toString(rssEnclosureLength), rssEnclosureType}); 181 RSSEnclosure rssEnclosureObject = new RSSEnclosure(rssEnclosureURL, rssEnclosureLength, rssEnclosureType); 182 183 entry.getMetaData().put(METADATA_RSS_ENCLOSURE, rssEnclosure); 184 entry.getMetaData().put(METADATA_ESS_ENCLOSURE_OBJECT, rssEnclosureObject); 185 if (_logger.isDebugEnabled()) { 186 _logger.debug("Added explicit enclosure: " + rssEnclosure); 187 } 188 } else { 189 if (BlojsomUtils.checkMapForKey(entry.getMetaData(), METADATA_RSS_ENCLOSURE)) { 190 String enclosureName = BlojsomUtils.getFilenameFromPath((String ) entry.getMetaData().get(METADATA_RSS_ENCLOSURE)); 191 File enclosure = new File (servletContext.getRealPath("/") + _resourcesDirectory + blog.getBlogId() + "/" + enclosureName); 192 if (enclosure.exists()) { 193 if (_logger.isDebugEnabled()) { 194 _logger.debug("Adding enclosure to entry for file: " + enclosureName); 195 } 196 197 MimetypesFileTypeMap mimetypesFileTypeMap = new MimetypesFileTypeMap (); 198 addAdditionalMimeTypes(mimetypesFileTypeMap); 199 String type = mimetypesFileTypeMap.getContentType(enclosure); 200 201 StringBuffer enclosureElement = new StringBuffer (); 202 String url = blog.getBlogBaseURL() + _resourcesDirectory + blog.getBlogId() + "/" + enclosure.getName(); 203 url = BlojsomUtils.escapeBrackets(url); 204 enclosureElement.append("<enclosure url=\""); 205 enclosureElement.append(url); 206 enclosureElement.append("\" length=\""); 207 enclosureElement.append(enclosure.length()); 208 enclosureElement.append("\" type=\""); 209 if (BlojsomUtils.checkNullOrBlank(type)) { 210 type = DEFAULT_MIME_TYPE; 211 } 212 enclosureElement.append(type); 213 enclosureElement.append("\" />"); 214 215 RSSEnclosure rssEnclosure = new RSSEnclosure(url, enclosure.length(), type); 216 entry.getMetaData().put(METADATA_RSS_ENCLOSURE, enclosureElement.toString()); 217 entry.getMetaData().put(METADATA_ESS_ENCLOSURE_OBJECT, rssEnclosure); 218 if (_logger.isDebugEnabled()) { 219 _logger.debug("Added enclosure: " + enclosureElement.toString()); 220 } 221 } 222 } 223 } 224 } 225 226 return entries; 227 } 228 229 235 public void cleanup() throws PluginException { 236 } 237 238 244 public void destroy() throws PluginException { 245 } 246 247 252 public void handleEvent(Event event) { 253 } 254 255 260 public void processEvent(Event event) { 261 if (event instanceof ProcessEntryEvent) { 262 if (_logger.isDebugEnabled()) { 263 _logger.debug("Handling process blog entry event"); 264 } 265 266 ProcessEntryEvent processBlogEntryEvent = (ProcessEntryEvent) event; 267 String blogId = processBlogEntryEvent.getBlog().getBlogId(); 268 269 Map templateAdditions = (Map ) processBlogEntryEvent.getContext().get("BLOJSOM_TEMPLATE_ADDITIONS"); 270 if (templateAdditions == null) { 271 templateAdditions = new TreeMap (); 272 } 273 274 templateAdditions.put(getClass().getName(), "#parse('" + RSS_ENCLOSURE_TEMPLATE + "')"); 275 processBlogEntryEvent.getContext().put("BLOJSOM_TEMPLATE_ADDITIONS", templateAdditions); 276 277 File resourceDirectory = new File (_servletConfig.getServletContext().getRealPath("/") + _resourcesDirectory + blogId + "/"); 279 Map resourceFilesMap = null; 280 if (resourceDirectory.exists()) { 281 File [] resourceFiles = resourceDirectory.listFiles(); 282 283 if (resourceFiles != null) { 284 resourceFilesMap = new HashMap (resourceFiles.length); 285 for (int i = 0; i < resourceFiles.length; i++) { 286 File resourceFile = resourceFiles[i]; 287 resourceFilesMap.put(resourceFile.getName(), resourceFile.getName()); 288 } 289 } 290 } else { 291 resourceFilesMap = new HashMap (); 292 } 293 294 if (processBlogEntryEvent.getEntry() != null) { 296 String currentEnclosure = (String ) processBlogEntryEvent.getEntry().getMetaData().get(METADATA_RSS_ENCLOSURE); 297 String currentEnclosureURL = (String ) processBlogEntryEvent.getEntry().getMetaData().get(RSS_ENCLOSURE_URL); 298 String currentEnclosureLength = (String ) processBlogEntryEvent.getEntry().getMetaData().get(RSS_ENCLOSURE_LENGTH); 299 String currentEnclosureType = (String ) processBlogEntryEvent.getEntry().getMetaData().get(RSS_ENCLOSURE_TYPE); 300 301 if (_logger.isDebugEnabled()) { 302 _logger.debug("Current enclosure: " + currentEnclosure); 303 } 304 processBlogEntryEvent.getContext().put(RSS_ENCLOSURE_ATTACHMENT, currentEnclosure); 305 processBlogEntryEvent.getContext().put(RSS_ENCLOSURE_URL_ITEM, BlojsomUtils.escapeBrackets(currentEnclosureURL)); 306 processBlogEntryEvent.getContext().put(RSS_ENCLOSURE_LENGTH_ITEM, currentEnclosureLength); 307 processBlogEntryEvent.getContext().put(RSS_ENCLOSURE_TYPE_ITEM, currentEnclosureType); 308 } 309 310 String rssEnclosure = BlojsomUtils.getRequestValue(METADATA_RSS_ENCLOSURE, processBlogEntryEvent.getHttpServletRequest()); 311 String rssEnclosureURL = BlojsomUtils.getRequestValue(RSS_ENCLOSURE_URL, processBlogEntryEvent.getHttpServletRequest()); 312 String rssEnclosureLength = BlojsomUtils.getRequestValue(RSS_ENCLOSURE_LENGTH, processBlogEntryEvent.getHttpServletRequest()); 313 String rssEnclosureType = BlojsomUtils.getRequestValue(RSS_ENCLOSURE_TYPE, processBlogEntryEvent.getHttpServletRequest()); 314 315 if (!BlojsomUtils.checkNullOrBlank(rssEnclosureURL) && (processBlogEntryEvent.getEntry() != null)) { 316 processBlogEntryEvent.getEntry().getMetaData().put(RSS_ENCLOSURE_URL, rssEnclosureURL); 317 if (BlojsomUtils.checkNullOrBlank(rssEnclosureLength) && BlojsomUtils.checkNullOrBlank(rssEnclosureType)) { 318 String [] enclosureProperties = discoverEnclosureProperties(rssEnclosureURL); 319 rssEnclosureLength = enclosureProperties[0]; 320 rssEnclosureType = enclosureProperties[1]; 321 } 322 323 processBlogEntryEvent.getEntry().getMetaData().put(RSS_ENCLOSURE_LENGTH, rssEnclosureLength); 324 processBlogEntryEvent.getEntry().getMetaData().put(RSS_ENCLOSURE_TYPE, rssEnclosureType); 325 processBlogEntryEvent.getContext().put(RSS_ENCLOSURE_URL_ITEM, BlojsomUtils.escapeBrackets(rssEnclosureURL)); 326 processBlogEntryEvent.getContext().put(RSS_ENCLOSURE_LENGTH_ITEM, rssEnclosureLength); 327 processBlogEntryEvent.getContext().put(RSS_ENCLOSURE_TYPE_ITEM, rssEnclosureType); 328 329 if (_logger.isDebugEnabled()) { 330 _logger.debug("Added/updated RSS enclosure (explict): " + rssEnclosureURL); 331 } 332 } else { 333 if (processBlogEntryEvent.getEntry() != null) { 334 processBlogEntryEvent.getEntry().getMetaData().remove(RSS_ENCLOSURE_URL); 335 processBlogEntryEvent.getEntry().getMetaData().remove(RSS_ENCLOSURE_TYPE); 336 processBlogEntryEvent.getEntry().getMetaData().remove(RSS_ENCLOSURE_LENGTH); 337 } 338 339 processBlogEntryEvent.getContext().remove(RSS_ENCLOSURE_URL_ITEM); 340 processBlogEntryEvent.getContext().remove(RSS_ENCLOSURE_TYPE_ITEM); 341 processBlogEntryEvent.getContext().remove(RSS_ENCLOSURE_LENGTH_ITEM); 342 343 if (!BlojsomUtils.checkNullOrBlank(rssEnclosure) && processBlogEntryEvent.getEntry() != null) { 344 processBlogEntryEvent.getEntry().getMetaData().put(METADATA_RSS_ENCLOSURE, rssEnclosure); 345 processBlogEntryEvent.getContext().put(RSS_ENCLOSURE_ATTACHMENT, rssEnclosure); 346 347 if (_logger.isDebugEnabled()) { 348 _logger.debug("Added/updated RSS enclosure: " + BlojsomUtils.getFilenameFromPath(rssEnclosure)); 349 } 350 } else { 351 if (processBlogEntryEvent.getEntry() != null) { 352 processBlogEntryEvent.getEntry().getMetaData().remove(METADATA_RSS_ENCLOSURE); 353 } 354 processBlogEntryEvent.getContext().remove(RSS_ENCLOSURE_ATTACHMENT); 355 } 356 } 357 358 resourceFilesMap = new TreeMap (resourceFilesMap); 359 processBlogEntryEvent.getContext().put("PLUGIN_RSS_ENCLOSURE_FILES", resourceFilesMap); 360 } 361 } 362 363 369 protected String [] discoverEnclosureProperties(String rssEnclosureURL) { 370 String [] enclosureProperties = new String []{"", ""}; 371 372 try { 373 if (!rssEnclosureURL.toLowerCase().startsWith("http://")) { 374 if (_logger.isDebugEnabled()) { 375 _logger.debug("RSS enclosure URL not an HTTP-accessible resource"); 376 } 377 } else { 378 URL enclosure = new URL (rssEnclosureURL); 379 HttpURLConnection httpURLConnection = (HttpURLConnection ) enclosure.openConnection(); 380 httpURLConnection.setRequestMethod("HEAD"); 381 httpURLConnection.connect(); 382 383 enclosureProperties[0] = Integer.toString(httpURLConnection.getContentLength()); 384 enclosureProperties[1] = httpURLConnection.getContentType(); 385 386 httpURLConnection.disconnect(); 387 } 388 } catch (Exception e) { 389 if (_logger.isErrorEnabled()) { 390 _logger.error("Error retrieving enclosure properties", e); 391 } 392 } 393 394 return enclosureProperties; 395 } 396 397 402 public class RSSEnclosure { 403 404 private String url; 405 private long length; 406 private String type; 407 408 415 public RSSEnclosure(String url, long length, String type) { 416 this.url = url; 417 this.length = length; 418 this.type = type; 419 } 420 421 426 public String getUrl() { 427 return url; 428 } 429 430 435 public long getLength() { 436 return length; 437 } 438 439 444 public String getType() { 445 return type; 446 } 447 } 448 } 449 450 | Popular Tags |