View Javadoc

1   /*
2    * Copyright 2000-2001,2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.jetspeed.portal.portlets.admin;
18  
19  //Element Construction Set
20  import org.apache.ecs.html.A;
21  import org.apache.ecs.html.Center;
22  import org.apache.ecs.html.Form;
23  import org.apache.ecs.html.Input;
24  import org.apache.ecs.html.Option;
25  import org.apache.ecs.html.P;
26  import org.apache.ecs.html.Select;
27  import org.apache.ecs.html.Table;
28  import org.apache.ecs.html.TextArea;
29  import org.apache.ecs.html.TD;
30  import org.apache.ecs.html.TR;
31  import org.apache.ecs.ConcreteElement;
32  import org.apache.ecs.ElementContainer;
33  import org.apache.ecs.StringElement;
34  
35  //Jetspeed stuff
36  import org.apache.jetspeed.portal.PortletException;
37  import org.apache.jetspeed.portal.portlets.AbstractPortlet;
38  import org.apache.jetspeed.cache.disk.DiskCacheEntry;
39  import org.apache.jetspeed.cache.disk.JetspeedDiskCache;
40  import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
41  import org.apache.jetspeed.services.logging.JetspeedLogger;
42  
43  //Jetspeed Content Markup support
44  import org.apache.jetspeed.xml.api.jcm.Content;
45  import org.apache.jetspeed.xml.api.jcm.Entry;
46  import org.apache.jetspeed.xml.api.jcm.Item;
47  
48  //turbine
49  import org.apache.turbine.util.ParameterParser;
50  import org.apache.turbine.util.DynamicURI;
51  import org.apache.turbine.util.RunData;
52  import org.apache.jetspeed.services.resources.JetspeedResources;
53  
54  //standard java stuff
55  import java.io.Reader;
56  import java.io.Writer;
57  import java.util.Hashtable;
58  import java.util.Vector;
59  
60  /***
61  Handles enumerating Portlets that are also applications
62  
63  @author <a href="mailto:burton@apache.org">Kevin A. Burton</a>
64  @version $Id: JetspeedContentAdmin.java,v 1.28 2004/02/23 03:26:19 jford Exp $ 
65  */
66  public class JetspeedContentAdmin extends AbstractPortlet 
67  {
68      /***
69       * Static initialization of the logger for this class
70       */    
71      private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(JetspeedContentAdmin.class.getName());
72      
73      /***
74      Used as the provider name key
75      */
76      public static final String PROVIDER_NAME_KEY = "provider-name";
77  
78      public static final String POST_ARTICLE = "Post Article";
79  
80      private Hashtable content = new Hashtable();
81      
82      /***
83      Get the content for this JCP Admin
84      */
85      public ConcreteElement getContent( RunData rundata ) {
86  
87          ParameterParser params = rundata.getParameters();
88          
89          String provider = params.getString( PROVIDER_NAME_KEY );
90          
91          if ( provider == null ) {
92              return this.getProviders( rundata );
93          } else if ( params.getString( POST_ARTICLE ) != null ) {
94              //post the article if the user has hit the submit button.
95              params.remove( PROVIDER_NAME_KEY );
96              params.remove( POST_ARTICLE );
97              return this.postArticle( provider, rundata );
98          } else {
99              //get the form if a provider is specified.
100             params.remove( PROVIDER_NAME_KEY );
101             return this.getForm( provider, rundata );
102         }
103      
104     }
105 
106     /***
107     */
108     public String getURL( String provider ) {
109 
110         return JetspeedResources.getString( "content.provider." + provider + ".url" );
111 
112     }
113     
114     /***
115     */
116     public synchronized ConcreteElement postArticle( String provider, RunData rundata ) {
117         ElementContainer ec = new ElementContainer();
118 
119         ParameterParser params = rundata.getParameters();        
120         
121         String topic = params.getString( "topic", "" );
122         String title = params.getString( "title", "" );
123         String link  = params.getString( "link", "" );
124         String description  = params.getString( "description", "" );
125         
126         //create the JCM item
127         Item item = new Item();
128         item.setTopic( topic );
129         item.setTitle( title );
130         item.setLink( link );
131         item.setDescription( description );
132         
133 
134         Content content = null;
135         try {
136             content = this.getContentMarkup( this.getURL( provider ) ).getContent();
137 
138 
139             //BEGIN reorg of the item list so that the new entry begins at the top
140             Vector v = new Vector();
141             
142             Item[] items = content.getChannel().getItem();
143             
144             for ( int i = 0; i < items.length; ++i ) {
145                 v.addElement( items[i] );
146             }
147 
148             v.insertElementAt( item, 0 );
149             
150             //now build this into a new array
151             
152             Item[] newItems = new Item[ v.size() ];
153             v.copyInto( newItems );
154             
155             content.getChannel().removeAllItem();
156             
157             //now go through all the new items and add those
158             for ( int i = 0; i < newItems.length; ++i ) {
159                 content.getChannel().addItem( newItems[i] );
160             }
161 
162             //END reorg of the item list so that the new entry begins at the top            
163             
164             //save the portlet markup after you have made the changes.
165             this.getContentMarkup( this.getURL( provider ) ).save();
166 
167         } catch ( Throwable t ) {
168             logger.error("Throwable", t);
169             return new StringElement( "Can't use this provider: " + t.getMessage() );
170         }
171         
172         ec.addElement( "Your article '" + title + "' has been posted within '" + topic + "'" );
173         
174         return ec;
175     }
176     
177     /***
178     Get a list of providers an provide a form for them.
179     */
180     public ConcreteElement getProviders( RunData rundata ) {
181         
182         ElementContainer root = new ElementContainer();
183         
184         root.addElement( new P().addElement( "Select a content provider: " ) );
185 
186         Vector v = JetspeedResources.getVector( JetspeedResources.CONTENT_PROVIDER_LIST_KEY );
187         
188         for ( int i = 0; i < v.size(); ++i ) {
189             
190             String provider = (String)v.elementAt( i );
191             
192             String title = JetspeedResources.getString( "content.provider." + provider + ".title" );
193 
194             DynamicURI uri = new DynamicURI( rundata );
195             uri.addQueryData( rundata.getParameters() );
196             uri.addQueryData( PROVIDER_NAME_KEY, provider );
197 
198             P row = new P().addElement(  new A( uri.toString() ).addElement( title ) )
199                            .addElement( " ( " )
200                            .addElement( new A( this.getBookmarklet( provider, rundata ) ).addElement( "Bookmarklet" ) ) 
201                            .addElement( " ) " );
202                            
203             root.addElement( row );
204             
205             
206         }
207         
208         return root;
209         
210     }
211 
212     
213     /***
214     Return a form that refresh the feed daemon
215     
216     @param provider The provider that you want to publish content to.
217     */
218     private ConcreteElement getForm( String provider, RunData rundata ) {
219         
220         DynamicURI duri = new DynamicURI( rundata );
221         
222         Form form = new Form().setAction(  duri.toString() );
223 
224         Table table = new Table().setBorder(0);
225         form.addElement( table );
226         
227 
228         ParameterParser params = rundata.getParameters();
229         
230         //get the default values if they were specified as params
231         String topic = params.getString( "topic", "" );
232         String title = params.getString( "title", "" );
233         String link  = params.getString( "link", "" );
234         String description  = params.getString( "description", "" );
235         
236 
237         //build a select box for adding topics to.
238         
239         Content content = null;
240         try {
241             content = this.getContentMarkup( this.getURL( provider ) ).getContent();
242         } catch ( Exception e ) {
243             logger.error("Exception",  e);
244             return new StringElement( "Can't use this provider: " + e.getMessage() );
245         }
246         
247         Select select = new Select();
248         select.setName( "topic" );
249 
250         //entry topics
251         Entry[] topics = content.getChannel().getTopics().getEntry();
252         
253         //populate the select box
254         for ( int i = 0; i < topics.length; ++i ) {
255             String name = topics[i].getName();
256             select.addElement( new Option( name ).addElement( name ) );
257         }
258 
259         
260         //fix me... this needs to be a SELECT box
261         table.addElement( getRow( "Topic: ", select ) );
262                                                        
263         table.addElement( getRow( "Title: ", new Input().setType("text")
264                                                        .setName("title")
265                                                        .setValue( title ) ) );
266 
267         table.addElement( getRow( "Link: ", new Input().setType("text")
268                                                       .setName("link")
269                                                       .setValue( link ) ) );
270 
271         table.addElement( new TR().addElement( new TD().setColSpan(2)
272             .addElement( new TextArea().setName("description")
273                                        .setCols( 65 )
274                                        .setRows( 15 )
275                                        .addElement( description ) ) ) );
276         
277         form.addElement( new Input().setType( "hidden" )
278                                     .setName( PROVIDER_NAME_KEY )
279                                     .setValue( provider ) );
280                                     
281         form.addElement( new Input().setType( "submit" )
282                                     .setName( POST_ARTICLE )
283                                     .setValue( POST_ARTICLE ) );
284 
285         return new Center( form );
286 
287     }
288 
289     /***
290     Get a row for adding it to a table.
291     */
292     private TR getRow( String title, ConcreteElement ce ) {
293 
294         int TITLE_WIDTH = 30;
295         
296         TR tr = new TR().addElement( new TD().setWidth( TITLE_WIDTH )
297                                              .addElement( title ) )
298                         .addElement( new TD().addElement( ce ) );
299         return tr;
300         
301     }
302 
303     /***
304     Get the jetspeed content from disk.
305     */
306     public ContentMarkup getContentMarkup( String url ) throws Exception {
307 
308         ContentMarkup cm = (ContentMarkup)this.content.get( url );
309         
310         if ( cm == null ) {
311             
312             cm = new ContentMarkup( url );
313             this.content.put( url, cm );
314             
315         }
316 
317         return cm;
318         
319     }
320     
321     /***
322     Init this 
323     */
324     public void init() throws PortletException {
325         this.setTitle("Jetspeed Content");
326         this.setDescription("Publish Jetspeed Content.");
327     }
328 
329     /***
330     Get the content of a bookmarklet for the given provider.
331     */
332     private String getBookmarklet( String provider, RunData rundata ) {
333         
334         ParameterParser params = rundata.getParameters();
335         
336         StringBuffer buff = new StringBuffer();
337         
338         //create the JavaScript entry
339         
340         buff.append( "JavaScript:" );
341         buff.append( "top.location = '" + 
342                      rundata.getServerScheme() +
343                      "://" + 
344                      rundata.getServerName() + 
345                    (rundata.getServerPort() != 80 ? ":" + 
346                      rundata.getServerPort() : "") + 
347                      rundata.getScriptName() + 
348                      "?select-panel=JetspeedContentAdmin" );
349         buff.append( "&provider-name=" + provider );
350         buff.append( "&title=' + escape( document.title ) + '&link=' + escape( top.location );" );
351 
352         
353         return buff.toString();
354     }
355     
356     //required options so that this portlet looks like an admin portlet...
357     
358     /***
359     */
360     public boolean getAllowEdit( RunData rundata ) {
361         return false;
362     }
363 
364     /***
365     */
366     public boolean getAllowMaximize( RunData rundata ) {
367         return false;
368     }
369     
370     
371 }
372 
373 
374 /***
375 Class for abstracting Jetspeed content markup parsing.  Handles updating the
376 content if it has been modified on disk.
377 
378 @author <a href="mailto:burton@apache.org">Kevin A. Burton</a>
379 @version $Id: JetspeedContentAdmin.java,v 1.28 2004/02/23 03:26:19 jford Exp $ 
380 */
381 class ContentMarkup {
382     
383     /***
384     The last modified date of this URL,
385     */
386     private long lastModified;
387     
388     /***
389     The Castor generated API.
390     */
391     private Content content = null;
392     
393     /***
394     The URL on which the JCM is based.
395     */
396     private String url = null;
397     
398     /***
399     Create a ContentMarkup and point it to the URL you want.
400     */
401     public ContentMarkup( String url ) throws Exception {
402         System.err.println("Content Markup url => " + url );
403         this.url = url;
404 
405         this.lastModified = JetspeedDiskCache.getInstance().getEntry( this.url ).getLastModified();
406 
407         //now parse out this URL so that is now in memory
408         this.parse();
409         
410     }
411     
412     /***
413     Get the Castor generated content for this ContentMarkup
414     */
415     public Content getContent() throws Exception {
416 
417         long recent = JetspeedDiskCache.getInstance().getEntry( this.url ).getLastModified();
418             
419         if ( recent == 0 || this.lastModified < recent ) {
420             this.parse();
421         }
422         
423         return this.content;
424     }
425 
426     /***
427     Save this JCM (hopefully updated JCM) to disk.
428     */
429     public synchronized void save() throws Exception {
430 
431         DiskCacheEntry  pde = JetspeedDiskCache.getInstance()
432             .getEntry( this.url );
433         Writer filewriter = pde.getWriter();
434         this.content.marshal( filewriter );
435         filewriter.close();
436 
437     }
438 
439     /***
440     Parse out the JCM and store it in memory
441     */
442     public synchronized void parse() throws Exception {
443 
444         Reader stream = JetspeedDiskCache.getInstance()
445             .getEntry( this.url ).getReader();
446         this.content = Content.unmarshal( stream );
447         stream.close();
448         
449     }
450     
451 }