001    /*
002     * Created on Jul 14, 2008
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
005     * the License. You may obtain a copy of the License at
006     *
007     * http://www.apache.org/licenses/LICENSE-2.0
008     *
009     * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
010     * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
011     * specific language governing permissions and limitations under the License.
012     *
013     * Copyright @2008-2010 the original author or authors.
014     */
015    package org.fest.swing.launcher;
016    
017    import static org.fest.swing.edt.GuiActionRunner.execute;
018    import static org.fest.swing.launcher.NewAppletViewerQuery.showAppletViewerWith;
019    import static org.fest.util.Strings.concat;
020    import static org.fest.util.Strings.isEmpty;
021    
022    import java.applet.Applet;
023    import java.applet.AppletStub;
024    import java.util.HashMap;
025    import java.util.Map;
026    
027    import org.fest.swing.annotation.RunsInEDT;
028    import org.fest.swing.applet.AppletViewer;
029    import org.fest.swing.applet.BasicAppletContext;
030    import org.fest.swing.applet.BasicAppletStub;
031    import org.fest.swing.edt.GuiQuery;
032    import org.fest.swing.exception.UnexpectedException;
033    import org.fest.swing.launcher.AppletParameter.AppletParameterBuilder;
034    
035    /**
036     * Understands a fluent interface for launching and testing <code>{@link Applet}</code>s.
037     * <p>
038     * An applet can be launched by passing its type as <code>String</code>, the actual type, or an instance of the
039     * applet to launch:
040     *
041     * <pre>
042     * {@link AppletViewer} viewer = AppletLauncher.{@link #applet(String) applet}(&quot;org.fest.swing.applet.MyApplet&quot;).{@link #start() start}();
043     *
044     * // or
045     *
046     *
047     * {@link AppletViewer} viewer = AppletLauncher.{@link #applet(Class) applet}(MyApplet.class).{@link #start() start}();
048     *
049     * // or
050     *
051     * {@link AppletViewer} viewer = AppletLauncher.{@link #applet(Applet) applet}(new MyApplet()).{@link #start() start}();
052     * </pre>
053     *
054     * </p>
055     * <p>
056     * In addition, we can pass parameters to the applet to launch. The parameters to pass are the same that are specified
057     * in the <a href="http://java.sun.com/docs/books/tutorial/deployment/applet/html.html"
058     * target="_blank">HTML "param" tag</a>:
059     *
060     * <pre>
061     * {@link AppletViewer} viewer = AppletLauncher.{@link #applet(Applet) applet}(new MyApplet())
062     *                                     .{@link #withParameters(Map) withParameters}(
063     *                                         {@link AppletParameter#name(String) name}(&quot;bgcolor&quot;).{@link AppletParameterBuilder#value(String) value}(&quot;blue&quot;),
064     *                                         {@link AppletParameter#name(String) name}(&quot;color&quot;).{@link AppletParameterBuilder#value(String) value}(&quot;red&quot;),
065     *                                         {@link AppletParameter#name(String) name}(&quot;pause&quot;).{@link AppletParameterBuilder#value(String) value}(&quot;200&quot;)
066     *                                      )
067     *                                     .{@link #start() start}();
068     *
069     * // or
070     *
071     * Map&lt;String, String&gt; parameters = new HashMap&lt;String, String&gt;();
072     * parameters.put(&quot;bgcolor&quot;, &quot;blue&quot;);
073     * parameters.put(&quot;color&quot;, &quot;red&quot;);
074     * parameters.put(&quot;pause&quot;, &quot;200&quot;);
075     *
076     * {@link AppletViewer} viewer = AppletLauncher.{@link #applet(Applet) applet}(new MyApplet()).{@link #withParameters(Map) withParameters}(parameters).{@link #start() start}();
077     *
078     *
079     * </pre>
080     *
081     * </p>
082     *
083     *
084     * @author Yvonne Wang
085     * @author Alex Ruiz
086     */
087    public class AppletLauncher {
088    
089      private final Applet applet;
090      private final Map<String, String> parameters = new HashMap<String, String>();
091    
092      /**
093       * Creates a new applet launcher. The applet to launch is a new instance of the given type. It is assumed that the
094       * given type has a default constructor.
095       * @param appletType the type of applet to instantiate.
096       * @return the created applet launcher.
097       * @throws NullPointerException if the given type name is <code>null</code>.
098       * @throws IllegalArgumentException if the given type name is empty.
099       * @throws IllegalArgumentException if the given type is not a subclass of <code>java.applet.Applet</code>.
100       * @throws UnexpectedException if the given type cannot be loaded.
101       * @throws UnexpectedException if a new instance of the given type cannot be instantiated.
102       */
103      @RunsInEDT
104      public static AppletLauncher applet(String appletType) {
105        if (appletType == null) throw new NullPointerException("The name of the applet type should not be null");
106        if (isEmpty(appletType)) throw new IllegalArgumentException("The name of the applet type should not be empty");
107        Class<?> type = load(appletType);
108        if (!(Applet.class.isAssignableFrom(type)))
109          throw new IllegalArgumentException(concat("The given type is not a subclass of ", Applet.class.getName()));
110        return instantiate(type);
111      }
112    
113      @RunsInEDT
114      private static Class<?> load(String typeName) {
115        try {
116          return Class.forName(typeName);
117        } catch (ClassNotFoundException e) {
118          throw cannotLoadType(typeName, e);
119        } catch (Exception e) {
120          throw cannotLoadType(typeName, e);
121        }
122      }
123    
124      private static UnexpectedException cannotLoadType(String typeName, Exception e) {
125        throw new UnexpectedException(concat("Unable to load class ", typeName), e);
126      }
127      
128      /**
129       * Creates a new applet launcher. The applet to launch is a new instance of the given type. It is assumed that the
130       * given type has a default constructor.
131       * @param appletType the type of applet to instantiate.
132       * @return the created applet launcher.
133       * @throws NullPointerException if the given type is <code>null</code>.
134       * @throws UnexpectedException if a new instance of the given type cannot be instantiated.
135       */
136      @RunsInEDT
137      public static AppletLauncher applet(Class<? extends Applet> appletType) {
138        if (appletType == null) throw new NullPointerException("The applet type should not be null");
139        return instantiate(appletType);
140      }
141    
142      private static AppletLauncher instantiate(final Class<?> appletType) {
143        try {
144          Object applet = execute(new GuiQuery<Object>() {
145            protected Object executeInEDT() throws Exception {
146              return appletType.newInstance();
147            }
148          });
149          return applet((Applet)applet);
150        } catch (Exception e) {
151          throw cannotInstantiateApplet(appletType.getName(), e);
152        }
153      }
154      
155      private static UnexpectedException cannotInstantiateApplet(String appletType, Exception cause) {
156        throw new UnexpectedException(concat("Unable to create a new instance of ", appletType), cause);
157      }
158    
159      /**
160       * Creates a new applet launcher.
161       * @param applet the applet to launch.
162       * @return the created applet launcher.
163       * @throws NullPointerException if the given applet is <code>null</code>.
164       */
165      public static AppletLauncher applet(Applet applet) {
166        return new AppletLauncher(applet);
167      }
168    
169      private AppletLauncher(Applet applet) {
170        if (applet == null) throw new NullPointerException("The applet to launch should not be null");
171        this.applet = applet;
172      }
173    
174      /**
175       * Sets the parameters for the applet to launch, as an alternative to
176       * <code>{@link #withParameters(AppletParameter...)}</code>.
177       * @param newParameters the parameters for the applet to launch.
178       * @return this launcher.
179       * @throws NullPointerException if <code>newParameters</code> is <code>null</code>.
180       */
181      public AppletLauncher withParameters(Map<String, String> newParameters) {
182        if (newParameters == null) throw new NullPointerException("The map of parameters should not be null");
183        parameters.clear();
184        parameters.putAll(newParameters);
185        return this;
186      }
187    
188      /**
189       * Sets the parameters for the applet to launch, as an alternative to <code>{@link #withParameters(Map)}</code>.
190       * @param newParameters the parameters for the applet to launch.
191       * @return this launcher.
192       * @throws NullPointerException if <code>newParameters</code> is <code>null</code>.
193       * @throws NullPointerException if any parameter is <code>null</code>.
194       */
195      public AppletLauncher withParameters(AppletParameter... newParameters) {
196        if (newParameters == null) throw new NullPointerException("The array of parameters should not be null");
197        parameters.clear();
198        for (AppletParameter parameter : newParameters) add(parameter);
199        return this;
200      }
201    
202      private void add(AppletParameter parameter) {
203        if (parameter == null) throw new NullPointerException("Found a null parameter");
204        parameters.put(parameter.name, parameter.value);
205      }
206    
207      /**
208       * Launches the applet in a <code>{@link AppletViewer}</code> (using implementations of
209       * <code>{@link BasicAppletStub}</code> and <code>{@link BasicAppletContext}</code>. To provide your own
210       * <code>{@link AppletStub}</code> create a new <code>{@link AppletViewer}</code> directly.
211       * The <code>AppletViewer</code> is created and launched in the event dispatch thread.
212       * @return the created <code>AppletViewer</code>.
213       */
214      public AppletViewer start() {
215        return showAppletViewerWith(applet, parameters);
216      }
217    }