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.ui.progress;
020
021import java.io.IOException;
022import java.util.HashMap;
023import java.util.List;
024import java.util.Map;
025import java.util.UUID;
026
027import javax.servlet.ServletException;
028import javax.servlet.http.HttpServletRequest;
029import javax.servlet.http.HttpServletResponse;
030
031import org.apache.log4j.Logger;
032import org.apache.wiki.ajax.WikiAjaxDispatcherServlet;
033import org.apache.wiki.ajax.WikiAjaxServlet;
034
035/**
036 *  Manages progressing items.  In general this class is used whenever JSPWiki
037 *  is doing something which may require a long time.  In addition, this manager
038 *  provides a JSON interface for finding remotely what the progress is.  The
039 *  JSON object name is JSON_PROGRESSTRACKER = "{@value #JSON_PROGRESSTRACKER}".
040 *
041 *  @since  2.6
042 */
043// FIXME: Needs synchronization, I think
044public class ProgressManager
045{
046    private Map<String,ProgressItem> m_progressingTasks = new HashMap<String,ProgressItem>();
047
048    /**
049     *  The name of the progress tracker JSON object.  The current value is "{@value}",
050     */
051    public static final String JSON_PROGRESSTRACKER = "progressTracker";
052
053    private static Logger log = Logger.getLogger( ProgressManager.class );
054
055    /**
056     *  Creates a new ProgressManager.
057     */
058    public ProgressManager()
059    {
060        //TODO: Replace with custom annotations. See JSPWIKI-566
061        WikiAjaxDispatcherServlet.registerServlet( JSON_PROGRESSTRACKER, new JSONTracker() );
062    }
063
064    /**
065     *  You can use this to get an unique process identifier.
066     *  @return A new random value
067     */
068    public String getNewProgressIdentifier()
069    {
070        return UUID.randomUUID().toString();
071    }
072
073    /**
074     *  Call this method to get your ProgressItem into the ProgressManager queue.
075     *  The ProgressItem will be moved to state STARTED.
076     *
077     *  @param pi ProgressItem to start
078     *  @param id The progress identifier
079     */
080    public void startProgress( ProgressItem pi, String id )
081    {
082        log.debug("Adding "+id+" to progress queue");
083        m_progressingTasks.put( id, pi );
084        pi.setState( ProgressItem.STARTED );
085    }
086
087    /**
088     *  Call this method to remove your ProgressItem from the queue (after which
089     *  getProgress() will no longer find it.  The ProgressItem will be moved to state
090     *  STOPPED.
091     *
092     *  @param id The progress identifier
093     */
094    public void stopProgress( String id )
095    {
096        log.debug("Removed "+id+" from progress queue");
097        ProgressItem pi = m_progressingTasks.remove( id );
098        if( pi != null ) pi.setState( ProgressItem.STOPPED );
099    }
100
101    /**
102     *  Get the progress in percents.
103     *
104     *  @param id The progress identifier.
105     *  @return a value between 0 to 100 indicating the progress
106     *  @throws IllegalArgumentException If no such progress item exists.
107     */
108    public int getProgress( String id )
109        throws IllegalArgumentException
110    {
111        ProgressItem pi = m_progressingTasks.get( id );
112
113        if( pi != null )
114        {
115            return pi.getProgress();
116        }
117
118        throw new IllegalArgumentException("No such id was found");
119    }
120
121    /**
122     *  Provides access to a progress indicator, assuming you know the ID.
123     *  Progress of zero (0) means that the progress has just started, and a progress of
124     *  100 means that it is complete.
125     */
126    public class JSONTracker implements WikiAjaxServlet
127    {
128        /**
129         *  Returns upload progress in percents so far.
130         *  @param progressId The string representation of the progress ID that you want to know the
131         *                    progress of.
132         *  @return a value between 0 to 100 indicating the progress
133         */
134        public int getProgress( String progressId )
135        {
136            return ProgressManager.this.getProgress( progressId );
137        }
138        
139        public String getServletMapping() {
140            return JSON_PROGRESSTRACKER;
141        }
142        
143        public void service(HttpServletRequest req, HttpServletResponse resp, String actionName, List<String> params)
144                throws ServletException, IOException 
145        {
146            log.debug("ProgressManager.doGet() START");
147            if (params.size()<1) {
148                return;
149            }
150            String progressId = params.get(0);
151            log.debug("progressId="+progressId);
152            String progressString = "";
153            try {
154                int progress = getProgress(progressId);
155                progressString = Integer.toString(progress);
156            } catch (IllegalArgumentException e) {
157                // ignore
158                log.debug("progressId "+progressId+" is no longer valid");
159            }
160            log.debug("progressString="+progressString);
161            resp.getWriter().write(progressString);
162            log.debug("ProgressManager.doGet() DONE");
163        }
164    }
165}