001/* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019package org.apache.wiki.rss; 020 021import org.apache.commons.lang3.time.DateFormatUtils; 022import org.apache.wiki.api.Release; 023import org.apache.wiki.api.core.Attachment; 024import org.apache.wiki.api.core.Context; 025import org.apache.wiki.api.core.ContextEnum; 026import org.apache.wiki.api.core.Engine; 027import org.apache.wiki.api.core.Page; 028import org.apache.wiki.api.exceptions.ProviderException; 029import org.apache.wiki.attachment.AttachmentManager; 030import org.jdom2.Element; 031import org.jdom2.Namespace; 032import org.jdom2.output.Format; 033import org.jdom2.output.XMLOutputter; 034 035import javax.servlet.ServletContext; 036import java.io.IOException; 037import java.io.StringWriter; 038import java.util.ArrayList; 039import java.util.Collection; 040import java.util.Date; 041import java.util.List; 042 043/** 044 * Provides an Atom 1.0 standard feed, with enclosures. 045 * 046 */ 047public class AtomFeed extends Feed { 048 049 private final Namespace m_atomNameSpace = Namespace.getNamespace("http://www.w3.org/2005/Atom"); 050 051 /** Defines a SimpleDateFormat string for RFC3339-formatted dates. */ 052 public static final String RFC3339FORMAT = "yyyy-MM-dd'T'HH:mm:ssZZ"; 053 054 /** 055 * Create a new AtomFeed for a given WikiContext. 056 * 057 * @param c A WikiContext. 058 */ 059 public AtomFeed( final Context c ) 060 { 061 super(c); 062 } 063 064 /** 065 * This is a bit complicated right now, as there is no proper metadata store in JSPWiki. 066 * 067 * @return An unique feed ID. 068 */ 069 private String getFeedID() 070 { 071 return m_wikiContext.getEngine().getBaseURL(); // FIXME: This is not a feed id 072 } 073 074 private String getEntryID( final Entry e ) 075 { 076 return e.getURL(); // FIXME: Not really a feed id! 077 } 078 079 private Collection<Element> getItems() { 080 final ArrayList< Element > list = new ArrayList<>(); 081 final Engine engine = m_wikiContext.getEngine(); 082 ServletContext servletContext = null; 083 if( m_wikiContext.getHttpRequest() != null ) { 084 servletContext = m_wikiContext.getHttpRequest().getSession().getServletContext(); 085 } 086 087 for( final Entry e : m_entries ) { 088 final Page p = e.getPage(); 089 final Element entryEl = getElement( "entry" ); 090 091 // Mandatory elements 092 entryEl.addContent( getElement( "id" ).setText( getEntryID( e ) ) ); 093 entryEl.addContent( getElement( "title" ).setAttribute( "type", "html" ).setText( e.getTitle() ) ); 094 entryEl.addContent( getElement( "updated" ).setText( DateFormatUtils.formatUTC( p.getLastModified(), RFC3339FORMAT ) ) ); 095 096 // Optional elements 097 entryEl.addContent( getElement( "author" ).addContent( getElement( "name" ).setText( e.getAuthor() ) ) ); 098 entryEl.addContent( getElement( "link" ).setAttribute( "rel", "alternate" ).setAttribute( "href", e.getURL() ) ); 099 entryEl.addContent( getElement( "content" ).setAttribute( "type", "html" ).setText( e.getContent() ) ); 100 101 // Check for enclosures 102 if( engine.getManager( AttachmentManager.class ).hasAttachments( p ) && servletContext != null ) { 103 try { 104 final List< Attachment > c = engine.getManager( AttachmentManager.class ).listAttachments( p ); 105 for( final Attachment att : c ) { 106 final Element attEl = getElement( "link" ); 107 attEl.setAttribute( "rel", "enclosure" ); 108 attEl.setAttribute( "href", engine.getURL( ContextEnum.PAGE_ATTACH.getRequestContext(), att.getName(), null ) ); 109 attEl.setAttribute( "length", Long.toString( att.getSize() ) ); 110 attEl.setAttribute( "type", getMimeType( servletContext, att.getFileName() ) ); 111 112 entryEl.addContent( attEl ); 113 } 114 } catch( final ProviderException ex ) { 115 // FIXME: log.info("Can't get attachment data",ex); 116 } 117 } 118 119 list.add( entryEl ); 120 } 121 122 return list; 123 } 124 125 /** 126 * {@inheritDoc} 127 */ 128 @Override 129 public String getString() { 130 final Element root = getElement("feed"); 131 final Engine engine = m_wikiContext.getEngine(); 132 133 Date lastModified = new Date(0L); 134 135 for( final Entry e : m_entries ) { 136 if( e.getPage().getLastModified().after( lastModified ) ) { 137 lastModified = e.getPage().getLastModified(); 138 } 139 } 140 141 // Mandatory parts 142 root.addContent( getElement( "title" ).setText( getChannelTitle() ) ); 143 root.addContent( getElement( "id" ).setText( getFeedID() ) ); 144 root.addContent( getElement( "updated" ).setText( DateFormatUtils.formatUTC( lastModified, RFC3339FORMAT ) ) ); 145 146 // Optional 147 // root.addContent( getElement("author").addContent(getElement("name").setText(format()))) 148 root.addContent( getElement( "link" ).setAttribute( "href", engine.getBaseURL() ) ); 149 root.addContent( getElement( "generator" ).setText( "JSPWiki " + Release.VERSTR ) ); 150 151 final String rssFeedURL = engine.getURL( ContextEnum.PAGE_NONE.getRequestContext(), "rss.jsp", 152 "page=" + engine.encodeName( m_wikiContext.getPage().getName() ) + 153 "&mode=" + m_mode + 154 "&type=atom" ); 155 final Element self = getElement( "link" ).setAttribute( "rel","self" ); 156 self.setAttribute( "href", rssFeedURL ); 157 root.addContent( self ); 158 159 // Items 160 root.addContent( getItems() ); 161 162 // aaand output 163 final XMLOutputter output = new XMLOutputter(); 164 output.setFormat( Format.getPrettyFormat() ); 165 166 try { 167 final StringWriter res = new StringWriter(); 168 output.output( root, res ); 169 170 return res.toString(); 171 } catch( final IOException e ) { 172 return null; 173 } 174 } 175 176 private Element getElement( final String name ) { 177 return new Element( name, m_atomNameSpace ); 178 } 179 180}