001    /*
002     * Copyright 1999-2001,2004 The Apache Software Foundation.
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */ 
016    
017    package org.apache.commons.workflow.io;
018    
019    
020    import java.io.BufferedInputStream;
021    import java.io.InputStream;
022    import java.io.InputStreamReader;
023    import java.io.IOException;
024    import java.net.MalformedURLException;
025    import java.net.URL;
026    import java.net.URLConnection;
027    import java.util.EmptyStackException;
028    import org.apache.commons.workflow.Context;
029    import org.apache.commons.workflow.StepException;
030    import org.apache.commons.workflow.base.BaseStep;
031    import org.apache.commons.workflow.util.WorkflowUtils;
032    
033    
034    /**
035     * <p>Retrieve the contents of a specified URL resource, and push the
036     * contents as a String object onto the evaluation stack.</p>
037     *
038     * <p>Supported Attributes:</p>
039     * <ul>
040     * <li><strong>url</strong> - URL of the resource to be retrieved, or
041     *     omitted to pop a computed String value from the top of the
042     *     evaluation stack.</li>
043     * </ul>
044     *
045     * <strong>DESIGN QUESTION - What about binary content?</strong>
046     *
047     * @version $Revision: 155475 $ $Date: 2005-02-26 13:31:11 +0000 (Sat, 26 Feb 2005) $
048     * @author Craig R. McClanahan
049     */
050    
051    public class GetStep extends BaseStep {
052    
053    
054        // ----------------------------------------------------------= Constructors
055    
056    
057        /**
058         * Construct a default instance of this Step.
059         */
060        public GetStep() {
061    
062            super();
063    
064        }
065    
066    
067        /**
068         * Construct an instance of this Step with the specified identifier.
069         *
070         * @param id Step identifier
071         */
072        public GetStep(String id) {
073    
074            super();
075            setId(id);
076    
077        }
078    
079    
080        /**
081         * Construct a fully configured instance of this Step.
082         *
083         * @param id Step identifier
084         * @param url Resource url
085         */
086        public GetStep(String id, String url) {
087    
088            super();
089            setId(id);
090            setUrl(url);
091    
092        }
093    
094    
095        // ------------------------------------------------------------- Properties
096    
097    
098        /**
099         * The URL of the resource to be retrieved.
100         */
101        protected String url = null;
102    
103        public String getUrl() {
104            return (this.url);
105        }
106    
107        public void setUrl(String url) {
108            this.url = url;
109        }
110    
111    
112        // --------------------------------------------------------- Public Methods
113    
114    
115        /**
116         * Perform the executable actions related to this Step, in the context of
117         * the specified Context.
118         *
119         * @param context The Context that is tracking our execution state
120         *
121         * @exception StepException if a processing error has occurred
122         */
123        public void execute(Context context) throws StepException {
124    
125            // Get the remote URL we will be contacting
126            Object remote = this.url;
127            URL remoteURL = null;
128            if (remote == null) {
129                try {
130                    remote = (String) context.pop();
131                } catch (EmptyStackException e) {
132                    throw new StepException("Evaluation stack is empty", this);
133                }
134            }
135            if (remote instanceof URL) {
136                remoteURL = (URL) remote;
137            } else if (remote instanceof String) {
138                try {
139                    remoteURL = new URL((String) remote);
140                } catch (MalformedURLException e) {
141                    throw new StepException("Invalid URL '" + remote + "'",
142                                            e, this);
143                }
144            } else {
145                try {
146                    remoteURL = new URL(remote.toString());
147                } catch (MalformedURLException e) {
148                    throw new StepException("Invalid URL '" + remote + "'",
149                                            e, this);
150                }
151            }
152    
153            // Define variables we will need later
154            URLConnection conn = null;
155            InputStream is = null;
156            BufferedInputStream bis = null;
157            InputStreamReader isr = null;
158            StringBuffer sb = null;
159            StepException se = null;
160    
161            try {
162    
163                // Open a connection to the specified URL
164                conn = remoteURL.openConnection();
165                conn.setDoInput(true);
166                conn.setDoOutput(false);
167                conn.connect();
168                int contentLength = conn.getContentLength();
169                if (contentLength < 2048)
170                    contentLength = 2048;
171                sb = new StringBuffer(contentLength);
172    
173                // Parse the character encoding to be used
174                String contentType = conn.getContentType();
175                String encoding =
176                    WorkflowUtils.parseCharacterEncoding(contentType);
177    
178                // Construct a suitable InputStreamReader
179                is = conn.getInputStream();
180                bis = new BufferedInputStream(is, 2048);
181                if (encoding == null)
182                    isr = new InputStreamReader(bis);
183                else
184                    isr = new InputStreamReader(bis, encoding);
185    
186                // Copy all characters from this resource
187                while (true) {
188                    int ch = isr.read();
189                    if (ch < 0)
190                        break;
191                    sb.append((char) ch);
192                }
193    
194                // Close the input file
195                isr.close();
196                isr = null;
197                bis = null;
198                is = null;
199    
200            } catch (IOException e) {
201    
202                se = new StepException("IOException processing '" + remoteURL +
203                                       "'", e, this);
204    
205            } finally {
206    
207                if (isr != null) {
208                    try {
209                        isr.close();
210                    } catch (Throwable t) {
211                        ;
212                    }
213                } else if (bis != null) {
214                    try {
215                        bis.close();
216                    } catch (Throwable t) {
217                        ;
218                    }
219                } else if (is != null) {
220                    try {
221                        is.close();
222                    } catch (Throwable t) {
223                        ;
224                    }
225                }
226    
227            }
228    
229            // Push results or throw exception as appropriate
230            if (se != null)
231                throw se;
232            context.push(sb.toString());
233    
234        }
235    
236    
237    }