[rfc][icedtea-web] plugin splash screen
Deepak Bhole
dbhole at redhat.com
Mon Feb 13 09:06:20 PST 2012
* Jiri Vanek <jvanek at redhat.com> [2012-02-13 10:36]:
> Hi!
>
> This is plugin's spalsh screen based on Deepak's old code.
> You can see imaged spalshscreen here: http://download.eng.brq.redhat.com/scratch/jvanek/pluginLoading.gif
> Before JVM actually starts, there is just gray box. Currently I have no idea how to get rid of it. But I'm also not sure if it is possible or if it have some value to solve it.
> The grey box AFTER the splash-screen is correctly loaded empty applet (sorry for providing such a dummy one:-/). In case 3.5mb animated gif is too big for you just check this stalled one - http://download.eng.brq.redhat.com/scratch/jvanek/screen55.gif ;)
>
> The diff in atachement is code of spalsh creen nearly identical with original Deepak's one - just adapted for head. I had just noticed that t is not at actual head - the diff of file b/netx/net/sourceforge/jnlp/Launcher.java is just "hardcoded" Danesh's fix for recent applet regression and have nothing to do with splash screen.
> The changes in testengine are just funny ones - for observering the spalsh screen, but I think they are worthy to be inside. In case that some test of splash screen will be in, they will be necessary.
> If you want to see the splash screen in work, make install and configure firefox, then check any applet;). If you want to see more of cycling sphere, you can start tests/netx/jnlp_testsengine/net/sourceforge/jnlp/ServerAccess.java class with -Dtest.server.dir setted correctly as tests do, add attached html file into this jnlp_server and lunch it... (It is how this gif was created).
>
> Any comments to current approach are more then welcomed!
>
> Things for future I'm thinking about
> - when applet will fail to load, something happens - eg text with exception, just sad emoticon with information about debuging console....
> - javaws splash screen - I think that when plugin have spalsh screen, then javaws should have it too, to be unified - My ideas are - at first use gif image for "java -splash" and then "quickly" replace him ASAP with true vector graphic. Both vorthy? Just vector graphics? Just animated gif? (not animated version of luncher is attached)
> - remake the loadng logo - I like Deepaks aproach, and I'm considering it as nice one. But my sense for art is Zero-one. If you would like to suggest different one, please keep in mind it msut be vector one. A can also visit few frends oriented to computer graphic (I mean art, no pure programming) and maybe we can find and create something better. But currently I consider it as waste of time.
>
>
I will let someone else review this since it would be unfair to review
my own old code :) One thing though -- this also includes
PluginSplashPanel2.java .. I think one of the classes was a test class
and the other one intended to be final. The *2 might have been the test
one..
Cheers,
Deepak
> Thanx for any thoughts!
>
> J.
> diff -r 528e354ff469 netx/net/sourceforge/jnlp/Launcher.java
> --- a/netx/net/sourceforge/jnlp/Launcher.java Thu Feb 02 16:15:27 2012 -0500
> +++ b/netx/net/sourceforge/jnlp/Launcher.java Mon Feb 13 15:57:17 2012 +0100
> @@ -708,6 +708,9 @@
>
> ThreadGroup group = Thread.currentThread().getThreadGroup();
>
> + // appletInstance is needed by ServiceManager when looking up
> + // services. This could potentially be done in applet constructor
> + // so initialize appletInstance before creating applet.
> AppletInstance appletInstance;
> if (cont == null)
> appletInstance = new AppletInstance(file, group, loader, null);
> @@ -716,10 +719,14 @@
>
> loader.setApplication(appletInstance);
>
> + // Initialize applet now that ServiceManager has access to its
> + // appletInstance.
> String appletName = file.getApplet().getMainClass();
> Class appletClass = loader.loadClass(appletName);
> Applet applet = (Applet) appletClass.newInstance();
> + // Finish setting up appletInstance.
> appletInstance.setApplet(applet);
> + appletInstance.getAppletEnvironment().setApplet(applet);
>
> setContextClassLoaderForAllThreads(appletInstance.getThreadGroup(), appletInstance.getClassLoader());
>
> diff -r 528e354ff469 netx/net/sourceforge/jnlp/NetxPanel.java
> --- a/netx/net/sourceforge/jnlp/NetxPanel.java Thu Feb 02 16:15:27 2012 -0500
> +++ b/netx/net/sourceforge/jnlp/NetxPanel.java Mon Feb 13 15:57:17 2012 +0100
> @@ -35,6 +35,7 @@
>
> import sun.applet.AppletViewerPanel;
> import sun.awt.SunToolkit;
> +import sun.awt.X11.XEmbeddedFrame;
>
> /**
> * This panel calls into netx to run an applet, and pipes the display
> @@ -46,6 +47,7 @@
> private PluginBridge bridge = null;
> private boolean exitOnFailure = true;
> private AppletInstance appInst = null;
> + private XEmbeddedFrame appletViewerFrame;
> private boolean appletAlive;
> private final String uKey;
>
> @@ -232,4 +234,14 @@
> SunToolkit.createNewAppContext();
> }
> }
> +
> + public XEmbeddedFrame getAppletViewerFrame() {
> + return appletViewerFrame;
> + }
> +
> + public void setAppletViewerFrame(XEmbeddedFrame appletViewerFrame) {
> + this.appletViewerFrame = appletViewerFrame;
> + }
> +
> +
> }
> diff -r 528e354ff469 netx/net/sourceforge/jnlp/runtime/AppletEnvironment.java
> --- a/netx/net/sourceforge/jnlp/runtime/AppletEnvironment.java Thu Feb 02 16:15:27 2012 -0500
> +++ b/netx/net/sourceforge/jnlp/runtime/AppletEnvironment.java Mon Feb 13 15:57:17 2012 +0100
> @@ -207,6 +207,20 @@
> }
>
> /**
> + * Set the applet of this environment; can only be called once.
> + */
> + public void setApplet(Applet applet) {
> + if (this.applet != null) {
> + if (JNLPRuntime.isDebug()) {
> + Exception ex = new IllegalStateException("Applet can only be set once.");
> + ex.printStackTrace();
> + }
> + return;
> + }
> + this.applet = applet;
> + }
> +
> + /**
> * Returns an enumeration that contains only the applet
> * from the JNLP file.
> */
> diff -r 528e354ff469 plugin/icedteanp/java/sun/applet/PaintingAndStroking.java
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/plugin/icedteanp/java/sun/applet/PaintingAndStroking.java Mon Feb 13 15:57:17 2012 +0100
> @@ -0,0 +1,42 @@
> +package sun.applet;
> +
> +import java.awt.BasicStroke;
> +import java.awt.Color;
> +import java.awt.GradientPaint;
> +import java.awt.Graphics;
> +import java.awt.Graphics2D;
> +import java.awt.geom.Ellipse2D;
> +
> +import javax.swing.JFrame;
> +
> +public class PaintingAndStroking
> + extends JFrame {
> + public static void main(String[] args) {
> + PaintingAndStroking f = new PaintingAndStroking();
> + f.setTitle("PaintingAndStroking v1.0");
> + f.setSize(300, 150);
> + //f.center();
> + f.setVisible(true);
> + }
> +
> + public void paint(Graphics g) {
> + Graphics2D g2 = (Graphics2D)g;
> + double x = 15, y = 50, w = 70, h = 70;
> + Ellipse2D e = new Ellipse2D.Double(x, y, w, h);
> + GradientPaint gp = new GradientPaint(75, 75, Color.white,
> + 95, 95, Color.gray, true);
> + // Fill with a gradient.
> + //g2.setPaint(gp);
> + //g2.fill(e);
> + // Stroke with a solid color.
> + e.setFrame(x + 100, y, w, h);
> + g2.setPaint(Color.black);
> + g2.setStroke(new BasicStroke(8));
> + //g2.draw(e);
> + // Stroke with a gradient.
> + e.setFrame(x + 200, y, w, h);
> + g2.setPaint(gp);
> + g2.draw(e);
> + }
> +}
> +
> diff -r 528e354ff469 plugin/icedteanp/java/sun/applet/PluginAppletViewer.java
> --- a/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java Thu Feb 02 16:15:27 2012 -0500
> +++ b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java Mon Feb 13 15:57:17 2012 +0100
> @@ -76,6 +76,7 @@
> import java.awt.event.WindowListener;
> import java.awt.print.PageFormat;
> import java.awt.print.Printable;
> +import java.awt.Component;
> import java.io.IOException;
> import java.io.InputStream;
> import java.io.PrintStream;
> @@ -93,10 +94,8 @@
> import java.security.PrivilegedExceptionAction;
> import java.util.Enumeration;
> import java.util.HashMap;
> -import java.util.Hashtable;
> import java.util.Iterator;
> import java.util.Map;
> -import java.util.Vector;
>
> import java.util.concurrent.ConcurrentHashMap;
> import java.util.concurrent.ConcurrentMap;
> @@ -106,6 +105,7 @@
> import java.util.concurrent.locks.ReentrantLock;
>
> import javax.swing.SwingUtilities;
> +import javax.swing.JPanel;
>
> import net.sourceforge.jnlp.NetxPanel;
> import net.sourceforge.jnlp.runtime.JNLPClassLoader;
> @@ -115,6 +115,8 @@
> import sun.misc.Ref;
>
> import com.sun.jndi.toolkit.url.UrlUtil;
> +import java.util.Hashtable;
> +import java.util.Vector;
>
> /**
> * Lets us construct one using unix-style one shot behaviors
> @@ -145,7 +147,12 @@
> @Override public void run() {
> panel.createNewAppContext();
> // create the frame.
> - PluginAppletViewer.framePanel(identifier, handle, panel);
> + int width = Integer.parseInt(atts.get("width"));
> + int height = Integer.parseInt(atts.get("height"));
> +
> + PluginDebug.debug("X and Y are: " + width + " " + height);
> + panel.setAppletViewerFrame(PluginAppletViewer.framePanel(identifier,handle, width, height, panel));
> +
> panel.init();
> // Start the applet
> initEventQueue(panel);
> @@ -198,6 +205,8 @@
> ie.printStackTrace();
> }
>
> + ((PluginAppletViewer)(panel.getAppletViewerFrame())).removeSplash();
> +
> AppletSecurityContextManager.getSecurityContext(0).associateSrc(panel.getAppletClassLoader(), doc);
> AppletSecurityContextManager.getSecurityContext(0).associateInstance(identifier, panel.getAppletClassLoader());
>
> @@ -323,26 +332,32 @@
> private Image bufFrameImg;
> private Graphics bufFrameImgGraphics;
>
> +
> + private PluginSplashPanel splashPanel;
> +
> /**
> * Null constructor to allow instantiation via newInstance()
> */
> public PluginAppletViewer() {
> }
>
> - public static void framePanel(int identifier, long handle, NetxPanel panel) {
> + public static PluginAppletViewer framePanel(int identifier,long handle, int width, int height, NetxPanel panel) {
>
> PluginDebug.debug("Framing ", panel);
> -
> - // SecurityManager MUST be set, and only privileged code may call reFrame()
> +
> + // SecurityManager MUST be set, and only privileged code may call framePanel()
> System.getSecurityManager().checkPermission(new AllPermission());
>
> PluginAppletViewer appletFrame = new PluginAppletViewer(handle, identifier, panel);
> -
> - appletFrame.add("Center", panel);
> - appletFrame.pack();
> -
> +
> appletFrame.appletEventListener = new AppletEventListener(appletFrame, appletFrame);
> panel.addAppletListener(appletFrame.appletEventListener);
> + // Clear bindings, if any
> + if (applets.containsKey(identifier)) {
> + PluginAppletViewer oldFrame = applets.get(identifier);
> + oldFrame.remove(panel);
> + panel.removeAppletListener(oldFrame.appletEventListener);
> + }
>
> appletsLock.lock();
> applets.put(identifier, appletFrame);
> @@ -350,6 +365,7 @@
> appletsLock.unlock();
>
> PluginDebug.debug(panel, " framed");
> + return appletFrame;
> }
>
> /**
> @@ -383,7 +399,53 @@
> };
>
> addWindowListener(windowEventListener);
> + final AppletPanel fPanel = panel;
> + try {
> + SwingUtilities.invokeAndWait(new Runnable() {
> + public void run() {
> + add("Center", fPanel);
> + fPanel.setVisible(false);
>
> + splashPanel = new PluginSplashPanel(fPanel.getWidth(), fPanel.getHeight());
> + splashPanel.spin();
> + PluginDebug.debug("Added splash " + splashPanel);
> +
> + add("Center", splashPanel);
> + pack();
> + }
> + });
> + } catch (Exception e) {
> + e.printStackTrace(); // Not much we can do other and print
> + }
> +
> + }
> +
> + public void removeSplash() {
> +
> + // Loading done. Remove splash screen.
> + splashPanel.stopSpinning();
> +
> + try {
> + SwingUtilities.invokeAndWait(new Runnable() {
> + public void run() {
> + splashPanel.setVisible(false);
> + remove(splashPanel);
> +
> + // Re-add the applet
> + remove(panel);
> + add(panel);
> + panel.setVisible(true);
> + pack();
> + }
> + });
> + } catch (Exception e) {
> + e.printStackTrace(); // Not much we can do other and print
> + }
> + }
> +
> + public void showErrorSplash () {
> + splashPanel.stopSpinning();
> + splashPanel.showError();
> }
>
> private static class AppletEventListener implements AppletListener {
> @@ -436,6 +498,14 @@
>
> break;
> }
> + case AppletPanel.APPLET_START: {
> + PluginDebug.debug("Error detected");
> + if (src.status != AppletPanel.APPLET_INIT && src.status != AppletPanel.APPLET_STOP) {
> + appletViewer.showErrorSplash();
> + }
> +
> + break;
> + }
> }
> }
> }
> @@ -517,6 +587,10 @@
> waitForAppletInit(applets.get(identifier).panel);
>
> // Should we proceed with reframing?
> + //appletFrame.removeSplash();
> + //framePanel(identifier, oldFrame.statusMsgStream, handle, applets.get(identifier).panel);
> + System.err.println("Init complete");
> +
> if (updateStatus(identifier, PAV_INIT_STATUS.REFRAME_COMPLETE).equals(PAV_INIT_STATUS.INACTIVE)) {
> destroyApplet(identifier);
> return;
> @@ -656,6 +730,8 @@
> */
> public static void waitForAppletInit(NetxPanel panel) {
>
> + System.err.println("Waiting for applet init");
> +
> // Wait till initialization finishes
> long maxTimeToSleep = APPLET_TIMEOUT;
>
> @@ -2097,7 +2173,7 @@
> * the parent class's update() just does a couple of checks (both of
> * which are accounted for) and then calls paint anyway.
> */
> - public void update(Graphics g) {
> + public void paint(Graphics g) {
>
> // If the image or the graphics don't exist, create new ones
> if (bufFrameImg == null || bufFrameImgGraphics == null) {
> @@ -2106,11 +2182,21 @@
> }
>
> // Paint off-screen
> - paint(bufFrameImgGraphics);
> + for (Component c: this.getComponents()) {
> + c.update(bufFrameImgGraphics);
> + }
>
> // Draw the painted image
> g.drawImage(bufFrameImg, 0, 0, this);
> }
> +
> + public void update(Graphics g) {
> + paint(g);
> + }
> +
> + private class PluginAppletPanel extends JPanel {
> + // Nothing to do . Yet..
> + }
>
> /**
> * Waits on a given condition queue until timeout.
> diff -r 528e354ff469 plugin/icedteanp/java/sun/applet/PluginSplashPanel.java
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/plugin/icedteanp/java/sun/applet/PluginSplashPanel.java Mon Feb 13 15:57:17 2012 +0100
> @@ -0,0 +1,579 @@
> +package sun.applet;
> +
> +import java.awt.BasicStroke;
> +import java.awt.Color;
> +import java.awt.Font;
> +import java.awt.FontMetrics;
> +import java.awt.Graphics;
> +import java.awt.Graphics2D;
> +import java.awt.Image;
> +import java.awt.Point;
> +import java.awt.RadialGradientPaint;
> +import java.awt.RenderingHints;
> +import java.awt.event.ComponentEvent;
> +import java.awt.event.ComponentListener;
> +import java.awt.geom.Ellipse2D;
> +import java.awt.geom.Point2D;
> +import java.awt.geom.RectangularShape;
> +import java.awt.geom.RoundRectangle2D;
> +import java.awt.image.BufferedImage;
> +
> +import javax.swing.JComponent;
> +import javax.swing.SwingUtilities;
> +import javax.swing.text.AttributeSet.ColorAttribute;
> +
> +public class PluginSplashPanel extends JComponent {
> +
> + /** Width of the plugin window */
> + private int pluginWidth;
> +
> + /** Height of the plugin window */
> + private int pluginHeight;
> +
> + /** Position of the spinner (angle in degrees) */
> + private int spinnerPos = 0;
> +
> + /** How much the spinner should move in each time slice */
> + private static final int spinFactor = 1;
> +
> + /** Frequency (per X iterations) at which dot animation moves forward */
> + private static final int dotAnimationFrequency = 18;
> +
> + /** The project name to display */
> + private static final String projDisplayName = "IcedTea-Web Plugin";
> +
> + /** The loading message */
> + private static final String loadingMsg = "Loading";
> +
> + /** The animated applet loading message (....'s are animated) */
> + private static final String animatedLoadingMsg = loadingMsg + "....";
> +
> + /** Number of dots after the loading message (to animate it) */
> + private int numDotsAfterLoadingMsg;
> +
> + /** Dark color of icedtea */
> + private Color darkIcedTeaColor = new Color(84, 0, 0);
> +
> + /** Light color of icedtea */
> + private Color lightIcedTeaColor = new Color(217, 191, 55);
> +
> + /** The corner width for the rectangles */
> + private int rectangleArcWidth;
> +
> + /** The inner rectangle */
> + private RectangularShape innerRectangle;
> +
> + /** The shadow of the inner rectangle */
> + private RectangularShape shadowRectangle;
> +
> + /** Returns the center circle */
> + private Ellipse2D centerCircle;
> +
> + /** Size of the shadow */
> + private int shadowSize;
> +
> + /** Whether to keep spinning */
> + volatile boolean spin = true;
> +
> + /** The background image (everything but the spinner) */
> + private BufferedImage panelBG;
> +
> + /** Image where everything is drawn off-screen */
> + private Image bufferedPanelImage;
> +
> + /** Graphics associated with the off-screen drawing image */
> + private Graphics bufferedImageGraphics;
> +
> + /** Minimum height/width for spinner */
> + private static final int minSizeForSpinner = 120;
> +
> + /** The minimum dimension (height of width) */
> + private int minDimension;
> +
> + /**
> + * Constructor. Takes an initial size for the panel and sets up listeners for resize
> + *
> + * @param initialPluginWidth The initial width of the plugin/panel
> + * @param initialPluginHeight The initial height of the plugin/panel
> + */
> + public PluginSplashPanel(final int initialPluginWidth, final int initialPluginHeight) {
> +
> + // Adjust vars based on initial size
> + adjustForSize(initialPluginWidth, initialPluginHeight);
> +
> + // Add a new listener for resizes
> + addComponentListener(new ComponentListener() {
> +
> + // Nothing to do for this
> + @Override
> + public void componentShown(ComponentEvent e) {
> + }
> +
> + // Re-adjust variables based on size
> + @Override
> + public void componentResized(ComponentEvent e) {
> + adjustForSize(getWidth(), getHeight());
> + }
> +
> + // Nothing to do for this
> + @Override
> + public void componentMoved(ComponentEvent e) {
> + }
> +
> + // Nothing to do for this
> + @Override
> + public void componentHidden(ComponentEvent e) {
> + }
> + });
> +
> + }
> +
> + /**
> + * Adjusts drawing related variables based on size of the panel
> + *
> + * @param pluginWidth The width of the panel
> + * @param pluginHeight The height of the panel
> + */
> + private void adjustForSize(int pluginWidth, int pluginHeight) {
> +
> + // Set the class-wide variables
> + this.pluginWidth = pluginWidth;
> + this.pluginHeight = pluginHeight;
> +
> + // The minimum dimension (either height or width)
> + minDimension = Math.min(pluginHeight, pluginWidth);
> +
> + // The arc-width -- default is 20, but set to 0 (sharp corners) if panel is too small
> + rectangleArcWidth = 20;
> + rectangleArcWidth = minDimension >= rectangleArcWidth*2 ? rectangleArcWidth : 0;
> +
> + // Size of the simulated shadow cast
> + shadowSize = Math.max(minDimension/20, 5);
> +
> + // The shadow rectangle shape
> + shadowRectangle = getShadowRectangle(new Point(shadowSize, shadowSize));
> +
> + // The inner (reddish-maroon) box
> + innerRectangle = getInnerRect(new Point(0, 0));
> +
> + // The circle in the center around which the spinner runs
> + centerCircle = getCenterCircle();
> +
> + // Calculate how many dots after the loading message (so that we can animate that)
> + // Do it in a quick and dirty way.. this code is called only once per splash
> +
> + String loadingMsgCopy = new String(animatedLoadingMsg);
> + numDotsAfterLoadingMsg = 0;
> + while (loadingMsgCopy.endsWith(".")) {
> +
> + // shorten string by 1
> + loadingMsgCopy = loadingMsgCopy.substring(0, loadingMsgCopy.length()-1);
> +
> + // increment dot count
> + numDotsAfterLoadingMsg++;
> + }
> +
> + // The background panel (all the satic stuff is pre-drawn for speed)
> + panelBG = getBufferedBgImage(false);
> + }
> +
> + /**
> + * Methods to start the animation in the splash panel.
> + *
> + * This method exits after starting a new thread to do the animation. It
> + * is synchronized to prevent multiple spin threads from being created.
> + */
> + public void spin () {
> +
> + /* If already spinning, don't do it again */
> + //if (spin)
> + // return;
> +
> + // Create a new thread to increment spinFactor and repaint
> + Thread t = new Thread () {
> +
> + public void run() {
> +
> + // While spinning
> + while (spin) {
> + try {
> +
> + // Reset spinner if we have crossed 360
> + if (spinnerPos > 360) {
> + spinnerPos = 0;
> + }
> +
> + // Move 1 degree per spin
> + spinnerPos += spinFactor;
> +
> + SwingUtilities.invokeAndWait(new Runnable() {
> + public void run() {
> +
> + // Force repaint
> + repaint();
> + }
> + });
> +
> + Thread.currentThread().sleep(30);
> +
> + if (spinnerPos%30 == 0) {
> + PluginDebug.debug(this + "spinning...");
> + }
> + } catch (Exception e) {
> + e.printStackTrace();
> + }
> + }
> + }
> + };
> +
> + t.start(); // Start spinning
> + }
> +
> + /**
> + * Stops the animation
> + */
> + public void stopSpinning() {
> + spin = false;
> + }
> +
> + /**
> + * Shows an error message
> + */
> + public void showError() {
> + panelBG = getBufferedBgImage(true);
> + repaint();
> + }
> +
> + /**
> + * Creates a background image with non-animated components and returns it
> + *
> + * @param errorBg Boolean indicating if the background is for an error.
> + * True indicates error background.
> + *
> + * @return The background image
> + */
> + public BufferedImage getBufferedBgImage(boolean errorBg) {
> +
> + // New static image for bg and text, so we don't have to redraw
> + BufferedImage bi = new BufferedImage(pluginWidth, pluginHeight, BufferedImage.TYPE_INT_RGB);
> +
> + // The graphics instance for the image
> + Graphics2D g2d = (Graphics2D) bi.getGraphics();
> +
> + // Text should look nice. Anti-alias it
> + Object defaultAntialias = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
> + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
> + RenderingHints.VALUE_ANTIALIAS_ON);
> +
> + // Start drawing the elements. Complex drawing is split off
> + // into smaller functions, rest is done here
> +
> + // == Back ground ==
> + // First, paint a while background
> + g2d.setPaint(new Color(255, 255, 255));
> + g2d.fillRect(0, 0, pluginWidth, pluginHeight);
> +
> + // == Shadow ==
> + drawShadow(g2d);
> +
> + // == Inner rectangle ==
> + // Set the rectangle color. Reddish-maroon for normal, dark gray for error
> + if (errorBg)
> + g2d.setPaint(Color.DARK_GRAY);
> + else
> + g2d.setPaint(darkIcedTeaColor);
> +
> + // Fill the inner rectangle with the above color
> + g2d.fill(innerRectangle);
> +
> + // == Project logo ==
> + drawTextAroundCenter(g2d, -0.5, 0, projDisplayName);
> +
> + // == center circle ==
> + if (!errorBg && minDimension >= minSizeForSpinner)
> + drawCenterCircle(g2d);
> +
> + // If there is an error, draw text as well
> + if (errorBg)
> + drawTextAroundCenter(g2d, 0, 0, "Loading failed");
> +
> + // Set anti-aliasing back to whatever it was
> + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, defaultAntialias);
> +
> + return bi;
> + }
> +
> + /**
> + * Returns the shadow shadow for the main rectangle
> + *
> + * @param topLeft The start (top-left) co-ordinates of the shadow
> + * @return The shadow rectangle shape
> + */
> + private RectangularShape getShadowRectangle(Point topLeft) {
> +
> + // The height and width of the shadow
> +
> + // When computing shadow size, we want to deduct from the applet size:
> + // 1) The top left starting point
> + // 2) The thickness of the shadow (since we use stroke to blend into a white bg)
> +
> + int shadowHeight = pluginHeight-topLeft.x-shadowSize;
> + int shadowWidth = pluginWidth-topLeft.y-shadowSize;
> +
> + return new RoundRectangle2D.Double(topLeft.x, topLeft.y,
> + shadowWidth, shadowHeight,
> + rectangleArcWidth, rectangleArcWidth);
> + }
> +
> + /**
> + * Returns the main rectangle shape
> + *
> + * @param topLeft The start (top-left) co-ordinates of the rectangle
> + * @return The main rectangle shape
> + */
> + private RectangularShape getInnerRect(Point topLeft) {
> +
> + // When computing rect size, we want to deduct from the applet size:
> + // 1) The top left starting point
> + // 2) The thickness of the shadow
> +
> + int rectHeight = pluginHeight - topLeft.x - shadowSize;
> + int rectWidth = pluginWidth - topLeft.y - shadowSize;
> +
> + return new RoundRectangle2D.Double(topLeft.x, topLeft.y,
> + rectWidth, rectHeight,
> + rectangleArcWidth, rectangleArcWidth);
> + }
> +
> + /**
> + * Returns the center circle around which the glowing sphere spins
> + *
> + * @return The circle shape
> + */
> + private Ellipse2D getCenterCircle() {
> +
> + // Radius should be decided by min of height/width
> + int diameter = Math.min((int) innerRectangle.getHeight(), (int) innerRectangle.getWidth());
> + diameter -= shadowSize*2; // Enough padding on all sides so that the glow stays in
> +
> + // Center of the rectangle
> + Point innerRectCenter = new Point((int) innerRectangle.getCenterX(), (int) innerRectangle.getCenterY());
> +
> + // Compute the top left point for the ellipse
> + Point topLeft = new Point(innerRectCenter.x - (int) (diameter/2), innerRectCenter.y - (int) (diameter/2));
> +
> + return new Ellipse2D.Double(topLeft.x, topLeft.y, diameter, diameter);
> + }
> +
> + /**
> + * Draws the shadow for the main rectangle
> + *
> + * @param g2d The Graphics2D object in which to draw
> + */
> + private void drawShadow(Graphics2D g2d) {
> +
> + /* Successively stroke with different colors from white
> + * to black, with white being the thickest stroke and black being
> + * the thinnest. This approach makes rendering a lot faster than
> + * using alpha composites.
> + */
> + for (int width=shadowSize; width > 0; width--) {
> + g2d.setColor(new Color((float) width/shadowSize, (float) width/shadowSize, (float) width/shadowSize));
> + g2d.setStroke(new BasicStroke(width));
> + g2d.draw(shadowRectangle);
> + }
> + }
> +
> + /**
> + * Draws text around the center area.
> + *
> + * This is a generic function that can draw text in the center as well
> + * as around it vertically (based on the offset). It can also be told
> + * to cut off the last X characters, which makes it useful for drawing
> + * animated text content.
> + *
> + * @param g2d The Graphics2D object
> + * @param heightOffset The offset from the center line in units of font height
> + * @param charsToCutOff How many characters to cut off from the string
> + * @param msg The text to draw
> + */
> + private void drawTextAroundCenter(Graphics2D g2d, double heightOffset,
> + int charsToCutOff, String msg) {
> +
> + // Font color = white
> + g2d.setPaint(new Color(1.0f,1.0f,1.0f));
> +
> + // Calculate font size
> + // First, get the lower bound of height/width
> + int minSize = Math.min(pluginHeight, pluginWidth);
> +
> + // Now, compute font size relative to the min size.
> + int fontSize = Math.max(minSize/16, 7);
> +
> + // Set the font
> + Font msgFont = new Font("Dialog", Font.BOLD, fontSize);
> + g2d.setFont(msgFont);
> +
> + // Calculate font location
> + FontMetrics fontMetrics;
> + int fontWidth;
> + int fontHeight;
> +
> + // Get the rendered font size
> + g2d.setFont(msgFont);
> + fontMetrics = g2d.getFontMetrics();
> + fontWidth = fontMetrics.stringWidth(msg);
> + fontHeight = fontMetrics.getHeight();
> +
> + // We now know the center of the rectangle, and the size of the text
> + // Compute were the font should be drawn
> +
> + // Horizontally
> + int fontXLocation = (int) (innerRectangle.getCenterX() - fontWidth/2); // half-width right from center
> +
> + // Vertically (center + offset)
> + int fontYLocation = (int) ((innerRectangle.getCenterY()) + heightOffset*fontHeight);
> +
> + // Finally, make sure the string will be in bounds
> + if (innerRectangle.getMinX() > fontXLocation /* top left X */ ||
> + innerRectangle.getMinY() > fontYLocation /* top left Y */ ||
> + innerRectangle.getMaxX() < fontXLocation + fontWidth /* bottom right X */ ||
> + innerRectangle.getMaxY() < fontYLocation + fontHeight /* bottom right Y */)
> + return;
> +
> + // Everything is within bounds
> + g2d.drawString(msg.substring(0, msg.length()-charsToCutOff), fontXLocation, fontYLocation);
> + }
> +
> + /**
> + * Draws the center circle along which a tiny sphere spins. The drawing is
> + * done in successive steps to give it a soft edge.
> + *
> + *@param g2d The Graphics2D instance to draw onto
> + */
> + private void drawCenterCircle(Graphics2D g2d) {
> +
> + // Calculate the thickness of the curcle
> + int circleThickness = Math.min((int) Math.min(pluginHeight, pluginWidth)/25, shadowSize); // never make it bigger than shadow
> +
> + // Keep stroking successively, the higher the stroke
> + // width, the lighter the color
> + for (int width=circleThickness; width > 0; width--) {
> + g2d.setColor(getCompositedColor(lightIcedTeaColor, darkIcedTeaColor, width, circleThickness));
> + g2d.setStroke(new BasicStroke(width));
> + g2d.draw(centerCircle);
> + }
> + }
> +
> + /**
> + * Function get composite color for use with iterative stroking for a soft edge
> + *
> + * This function returns a color between 2 given colors, based on the width of
> + * the stroke (higher width = most toward end color)
> + *
> + * @param start The start color
> + * @param end The end color
> + * @param width The width of the current stroke
> + * @param totalWidth Total width across which the stroking will be done
> + * @return The resulting composite color
> + */
> + private Color getCompositedColor(Color start, Color end, float width, float totalWidth) {
> +
> + // Find the distance between the colors
> + int rColorDistance = start.getRed() - end.getRed();
> + int gColorDistance = start.getGreen() - end.getGreen();
> + int bColorDistance = start.getBlue() - end.getBlue();
> +
> + // Compute the fraction by which it should be incremented
> + int rIncr = (int) (((float) rColorDistance * width)/totalWidth);
> + int gIncr = (int) (((float) gColorDistance * width)/totalWidth);
> + int bIncr = (int) (((float) bColorDistance * width)/totalWidth);
> +
> + return new Color(start.getRed() - rIncr, start.getGreen() - gIncr, start.getBlue() - bIncr);
> + }
> +
> + /**
> + * Draws the spinner based on spinner position
> + *
> + * @param g2d The Graphics2D object to draw on
> + */
> + private void drawSpinner(Graphics2D g2d) {
> +
> + // Do nothing when we are not spinning
> + if (!spin)
> + return;
> +
> + // Use anti-aliasing to make things look good
> + Object defaultAntialias = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
> + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
> + RenderingHints.VALUE_ANTIALIAS_ON);
> +
> + /* To show the "...." animation, we want to draw a new dot every
> + * X paint calls (where X is perfectly divisible by 360).
> + * So divide position by dotAnimationFrequency and mod by number
> + * of dots + 1 (the +1 because there are max + 1 states including
> + * the case of 0 dots)
> + */
> +
> + // Figure out characters (dots) to cut
> + int charsToCut = numDotsAfterLoadingMsg /*total */ -
> + (spinnerPos/dotAnimationFrequency)%(numDotsAfterLoadingMsg+1) /* how many to cut off */;
> +
> + // Draw the text
> + drawTextAroundCenter(g2d, 0.5, charsToCut, animatedLoadingMsg);
> +
> + if (minDimension < minSizeForSpinner)
> + return;
> +
> + // In the parametric form, we can compute the positions on the
> + // circumference using the equations:
> +
> + // x = x_center + radius*cos(t);
> + // y = y_center + radius*sin(t);
> +
> + // Where t is the angle from the X axis (in degrees)
> + float radius = (float) centerCircle.getWidth()/2;
> +
> + int x = (int) (centerCircle.getCenterX() + radius * (Math.cos(Math.toRadians(spinnerPos))));
> + int y = (int) (centerCircle.getCenterY() + radius * (Math.sin(Math.toRadians(spinnerPos))));
> +
> + // The spinning sphere size
> + int sphereSize = (int) (shadowSize);
> +
> + // Draw the sphere
> + Point2D center = new Point2D.Float(x, y);
> + float[] dist = {0.0f, 1.0f};
> + Color[] colors = {lightIcedTeaColor, darkIcedTeaColor};
> + RadialGradientPaint p = new RadialGradientPaint(center, sphereSize, dist, colors);
> + g2d.setPaint(p);
> + g2d.fillOval(x-sphereSize, y-sphereSize, sphereSize*2, sphereSize*2);
> +
> + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, defaultAntialias);
> + }
> +
> + @Override
> + public void paint(Graphics g) {
> +
> + Graphics2D g2d = (Graphics2D)g;
> +
> + // Draw the background
> + g2d.drawImage(panelBG, 0, 0, null);
> +
> + // Draw the spinner
> + drawSpinner(g2d);
> + }
> +
> + @Override
> + public void update (Graphics g) {
> +
> + // If the buffered image or graphics don't exit, create them
> + if (bufferedPanelImage == null || bufferedImageGraphics == null) {
> + bufferedPanelImage = createImage(pluginWidth, pluginHeight);
> + bufferedImageGraphics = bufferedPanelImage.getGraphics ();
> + }
> +
> + paint(bufferedImageGraphics);
> + g.drawImage(bufferedPanelImage, 0, 0, this);
> + }
> +
> +}
> \ No newline at end of file
> diff -r 528e354ff469 plugin/icedteanp/java/sun/applet/PluginSplashPanel2.java
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/plugin/icedteanp/java/sun/applet/PluginSplashPanel2.java Mon Feb 13 15:57:17 2012 +0100
> @@ -0,0 +1,273 @@
> +package sun.applet;
> +
> +import java.awt.BasicStroke;
> +import java.awt.Color;
> +import java.awt.Font;
> +import java.awt.FontMetrics;
> +import java.awt.GradientPaint;
> +import java.awt.Graphics;
> +import java.awt.Graphics2D;
> +import java.awt.Image;
> +import java.awt.LinearGradientPaint;
> +import java.awt.MultipleGradientPaint;
> +import java.awt.Paint;
> +import java.awt.Point;
> +import java.awt.Rectangle;
> +import java.awt.RenderingHints;
> +import java.awt.geom.RoundRectangle2D;
> +import java.awt.image.BufferedImage;
> +
> +import javax.swing.JComponent;
> +import javax.swing.SwingUtilities;
> +
> +public class PluginSplashPanel2 extends JComponent {
> +
> + /** Width of the plugin window */
> + int pluginWidth;
> +
> + /** Height of the plugin window */
> + int pluginHeight;
> +
> + /** Minimum width for text to appear */
> + int minWidthForText = 140;
> +
> + /** Minimum height for text to appear */
> + int minHeightForText = 65;
> +
> + /** The height of the spinners */
> + int spinnerHeight = 10;
> +
> + /** The width of each of the spinners */
> + int spinnerWidth;
> +
> + /** How much the bars should move in each time slice */
> + int spinnerSpinFactor;
> +
> + /** Font for the plugin name */
> + Font pluginNameStrFont;
> +
> + /** Font for the loading msg */
> + Font loadingMsgFont;
> +
> + /** The plugin name to display */
> + String pluginNameStr = "";
> +
> + /** The applet loading message */
> + String loadingMsg = "Applet Loading...";
> +
> + /** Dark color of icedtea */
> + Color darkIcedTeaColor = new Color(84, 0, 0);
> +
> + /** Light color of icedtea */
> + Color lightIcedTeaColor = new Color(217, 191, 55);
> +
> + Point shadowPosition = new Point(10, 10);
> + int shadowSize = 20;
> + int spinnerCorePos;
> +
> + volatile boolean spin = true;
> +
> + BufferedImage panelBG;
> + Image bufferedPanelImage;
> + Graphics bufferedImageGraphics;
> +
> + public PluginSplashPanel2(int pluginWidth, int pluginHeight) {
> + this.pluginWidth = pluginWidth;
> + this.pluginHeight = pluginHeight;
> +
> + spinnerWidth = pluginWidth/2;
> + spinnerSpinFactor = pluginWidth/50;
> +
> + spinnerCorePos = 0;
> +
> + int largeFontSize = 25;
> + int smallFontSize = 15;
> +
> + // For each 100 increase above min height and width, increase font by 5
> + int widthOverMin = pluginWidth - minWidthForText;
> + int heightOverMin = pluginHeight - minHeightForText;
> +
> + int sizeIncrease = Math.min(widthOverMin/100, heightOverMin/100)*5;
> +
> + largeFontSize += sizeIncrease;
> + smallFontSize += sizeIncrease;
> +
> + pluginNameStrFont = new Font("Monospaced", Font.BOLD, largeFontSize);
> + loadingMsgFont = new Font("Dialog", Font.BOLD, smallFontSize);
> +
> + panelBG = getBufferedBgImage();
> + }
> +
> + public void spin () {
> + int decFactor = -spinnerSpinFactor;
> +
> + Thread t = new Thread () {
> +
> + public void run() {
> +
> + while (spin) {
> + try {
> +
> + if (spinnerCorePos >= pluginWidth) {
> + spinnerCorePos = 0;
> + }
> +
> + spinnerCorePos += spinnerSpinFactor;
> +
> + SwingUtilities.invokeAndWait(new Runnable() {
> + public void run() {
> + repaint();
> + }
> + });
> +
> + Thread.currentThread().sleep(50);
> + } catch (Exception e) {
> + e.printStackTrace();
> + }
> + }
> + }
> + };
> +
> + t.start();
> + }
> +
> + public void stopSpinning() {
> + spin = false;
> + }
> +
> + /**
> + * Creates a background image and returns it
> + *
> + * @return The background image
> + */
> + public BufferedImage getBufferedBgImage() {
> +
> + BufferedImage bi = new BufferedImage(pluginWidth, pluginHeight, BufferedImage.TYPE_INT_RGB);
> + int arcWidth = 20;
> +
> + Graphics2D g2d = (Graphics2D) bi.getGraphics();
> +
> + // Text should look nice. Anti-alias it
> + Object defaultAntialias = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
> + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
> + RenderingHints.VALUE_ANTIALIAS_ON);
> +
> + // white background
> + g2d.setPaint(new Color(255, 255, 255));
> + g2d.fillRect(0, 0, pluginWidth, pluginHeight);
> +
> + // Create the shadow first
> +
> + RoundRectangle2D rect = new RoundRectangle2D.Double(
> + shadowPosition.x, shadowPosition.y,
> + pluginWidth-shadowPosition.x-shadowSize,
> + pluginHeight-shadowPosition.y-shadowSize,
> + arcWidth, arcWidth);
> + for (int width=shadowSize; width > 0; width--) {
> + // Thicker == lighter
> + g2d.setColor(new Color((float) width/shadowSize, (float) width/shadowSize, (float) width/shadowSize));
> + g2d.setStroke(new BasicStroke(width));
> + g2d.draw(rect);
> + }
> +
> + // Create the center rectangle
> + Point rectPosition = new Point(5,5);
> + rect = new RoundRectangle2D.Double(
> + rectPosition.x, rectPosition.y,
> + pluginWidth-rectPosition.x-shadowSize,
> + pluginHeight-rectPosition.y-shadowSize,
> + arcWidth, arcWidth);
> + g2d.setPaint(new GradientPaint(0, pluginHeight, darkIcedTeaColor, 0, 0, lightIcedTeaColor, false));
> + g2d.fill(rect);
> +
> + // Border for center rectangle with a "glow"
> + g2d.setPaint(new Color(1.0f,1.0f,1.0f));
> + //g2d.drawRoundRect(5, 5, pluginWidth-30, pluginHeight-30, 20, 20);
> +
> +
> + FontMetrics fontMetrics;
> +
> + int fontWidth;
> + int fontHeight;
> +
> + // Plugin name is printed only if width and height exceeds a certain size
> + if (pluginWidth >= 160 && pluginHeight >= 90) {
> + g2d.setFont(pluginNameStrFont);
> + fontMetrics = g2d.getFontMetrics();
> + fontWidth = fontMetrics.stringWidth(pluginNameStr);
> + fontHeight = fontMetrics.getAscent();
> +
> + /* lower left X */
> + int x = pluginWidth/2 - 10 /* center */ - fontWidth/2;
> +
> + /* lower left Y */
> + int y = pluginHeight/2 /* center */ - 25 /* center of rectangle */ + fontHeight/2 /* Height of font */;
> + if (y >= pluginHeight - 60 /* If it clashes with "Applet Loading..." */ )
> + y = pluginHeight - 65;
> +
> + g2d.drawString(pluginNameStr, x, y);
> + }
> +
> + // Applet loading message is only if width and height exceeds a certain size
> +
> + if (pluginWidth >= 140 && pluginHeight >= 65) {
> + g2d.setFont(loadingMsgFont);
> + fontMetrics = g2d.getFontMetrics();
> + fontWidth = fontMetrics.stringWidth(loadingMsg);
> + fontHeight = fontMetrics.getAscent();
> +
> + g2d.drawString(loadingMsg, pluginWidth-fontWidth-shadowSize-5, pluginHeight - spinnerHeight - shadowSize - 20 /* Padding */);
> + }
> +
> + // Done drawing text. Set back to what it was before
> + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
> + defaultAntialias);
> +
> + return bi;
> +
> + }
> +
> + @Override
> + public void paint(Graphics g) {
> +
> + Graphics2D g2d = (Graphics2D)g;
> + Paint defaultPaint = g2d.getPaint();
> +
> + Color centerColor = lightIcedTeaColor;
> + Color edgeColor = darkIcedTeaColor;
> +
> + g2d.drawImage(panelBG, 0, 0, null);
> +
> + System.err.println(spinnerCorePos);
> +
> + // Create a small rectangle
> + Rectangle rect = new Rectangle(5, pluginHeight-shadowSize-spinnerHeight-10, (pluginWidth-shadowSize-5), spinnerHeight);
> +
> + Color spinnerEdgeColor = new Color(
> + darkIcedTeaColor.getRGBColorComponents(null)[0],
> + darkIcedTeaColor.getRGBColorComponents(null)[1],
> + darkIcedTeaColor.getRGBColorComponents(null)[2],
> + 0.0f);
> +
> + //LinearGradientPaint lGp = new LinearGradientPaint((float) spinnerCorePos-100, 0f, (float) spinnerCorePos+100, 0f, new float[]{0.0f, 0.5f, 1.0f}, new Color[]{spinnerEdgeColor, lightIcedTeaColor, spinnerEdgeColor}, MultipleGradientPaint.CycleMethod.NO_CYCLE);
> + GradientPaint gp = new GradientPaint((float) spinnerCorePos-100, 0f, lightIcedTeaColor, (float) spinnerCorePos, 0f, darkIcedTeaColor);
> + g2d.setPaint(gp);
> + g2d.fill(rect);
> +
> + PluginDebug.debug("Painted " + g2d.hashCode());
> + }
> +
> + public void update (Graphics g) {
> +
> + if (bufferedPanelImage == null || bufferedImageGraphics == null) {
> + bufferedPanelImage = createImage(pluginWidth, pluginHeight);
> + bufferedImageGraphics = bufferedPanelImage.getGraphics ();
> + }
> +
> + PluginDebug.debug("Updating splash");
> +
> + paint(bufferedImageGraphics);
> + g.drawImage(bufferedPanelImage, 0, 0, this);
> + }
> +
> +}
> \ No newline at end of file
> diff -r 528e354ff469 plugin/icedteanp/java/sun/applet/PluginSplashPanelTest.java
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/plugin/icedteanp/java/sun/applet/PluginSplashPanelTest.java Mon Feb 13 15:57:17 2012 +0100
> @@ -0,0 +1,76 @@
> +package sun.applet;
> +import java.awt.BorderLayout;
> +import java.awt.Container;
> +import java.awt.event.ComponentEvent;
> +import java.awt.event.ComponentListener;
> +import java.awt.event.WindowAdapter;
> +import java.awt.event.WindowEvent;
> +
> +import javax.swing.JFrame;
> +import javax.swing.SwingUtilities;
> +
> +
> +public class PluginSplashPanelTest extends JFrame {
> +
> + static int width = 40; //860;
> + static int height = 60; //610;
> +
> + static PluginSplashPanel panel;
> +
> + public PluginSplashPanelTest() {
> +
> + setSize(width, height);
> +
> + panel = new PluginSplashPanel(width, height-20);
> + setLayout(new BorderLayout());
> + getContentPane().add(panel, BorderLayout.CENTER);
> +
> + setVisible(true);
> +
> + addComponentListener(new ComponentListener() {
> +
> + @Override
> + public void componentShown(ComponentEvent e) {
> + }
> +
> + @Override
> + public void componentResized(ComponentEvent e) {
> + panel.setSize(getWidth(), getHeight()-20);
> + }
> +
> + @Override
> + public void componentMoved(ComponentEvent e) {
> + }
> +
> + @Override
> + public void componentHidden(ComponentEvent e) {
> + }
> + });
> + }
> +
> + public static void main( String args[] ) {
> + PluginSplashPanelTest app = new PluginSplashPanelTest();
> +
> + app.addWindowListener(
> + new WindowAdapter() {
> + public void windowClosing( WindowEvent e )
> + {
> + System.exit( 0 );
> + }
> + }
> + );
> +
> + panel.spin();
> +
> + /*try {
> + Thread.sleep(2000);
> + } catch (Exception e) {
> +
> + }
> +
> + panel.stopSpinning();
> + panel.showError();*/
> +
> + }
> +}
> +
> diff -r 528e354ff469 tests/netx/jnlp_testsengine/net/sourceforge/jnlp/ServerAccess.java
> --- a/tests/netx/jnlp_testsengine/net/sourceforge/jnlp/ServerAccess.java Thu Feb 02 16:15:27 2012 -0500
> +++ b/tests/netx/jnlp_testsengine/net/sourceforge/jnlp/ServerAccess.java Mon Feb 13 15:57:17 2012 +0100
> @@ -53,6 +53,7 @@
> import java.net.MalformedURLException;
> import java.net.ServerSocket;
> import java.net.Socket;
> +import java.net.SocketException;
> import java.net.URI;
> import java.net.URL;
> import java.net.URLDecoder;
> @@ -117,11 +118,27 @@
>
> /**
> * main method of thos class prints out random free port
> + * or runs server
> + * param "port" prints out the port
> + * nothing or number will run sefrver on random(or on number specified)
> + * port in -Dtest.server.dir
> */
> - public static void main(String[] args) throws IOException {
> - int i = findFreePort();
> - System.out.println(i);
> + public static void main(String[] args) throws Exception {
> + if (args.length > 0 && args[0].equalsIgnoreCase("port")) {
> + int i = findFreePort();
> + System.out.println(i);
> + System.exit(0);
> + } else {
> + int port = 44321;
> + if (args.length > 0) {
> + port=new Integer(args[0]);
> + }
> + getIndependentInstance(port);
> + while (true) {
> + Thread.sleep(1000);
> + }
>
> + }
> }
>
> /**
> @@ -167,7 +184,22 @@
> */
> public static ServerLauncher getIndependentInstance() {
> String dir = (System.getProperty(TEST_SERVER_DIR));
> - return getIndependentInstance(dir);
> + try{
> + return getIndependentInstance(dir, findFreePort());
> + }catch (Exception ex){
> + throw new RuntimeException(ex);
> + }
> + }
> +
> +
> + /**
> + *
> + * @return new not cached iserver instance on random port,
> + * usefull for testing application loading from different url then base
> + */
> + public static ServerLauncher getIndependentInstance(int port) {
> + String dir = (System.getProperty(TEST_SERVER_DIR));
> + return getIndependentInstance(dir,port);
> }
>
> /**
> @@ -175,14 +207,13 @@
> * @return new not cached iserver instance on random port upon custom www root directory,
> * usefull for testing application loading from different url then base
> */
> - public static ServerLauncher getIndependentInstance(String dir) {
> + public static ServerLauncher getIndependentInstance(String dir, int port) {
>
>
> if (dir == null || dir.trim().length() == 0 || !new File(dir).exists() || !new File(dir).isDirectory()) {
> throw new RuntimeException("test.server.dir property must be set to valid directory!");
> }
> try {
> - int port = findFreePort();
> ServerLauncher lServerLuncher = new ServerLauncher(port, new File(dir));
> new Thread(lServerLuncher).start();
> return lServerLuncher;
> @@ -314,6 +345,13 @@
> Assert.assertEquals(new File(dirUrlContent.trim()), server.getDir());
> Assert.assertEquals(new Integer(portUrlContent.trim()), server.getPort());
>
> + URL fastUrl = new URL("http", "localhost", server.getPort(), "/simpletest1.jnlp");
> + URL slowUrl = new URL("http", "localhost", server.getPort(), "/XslowXsimpletest1.jnlp");
> +
> + String fastUrlcontent = getContentOfStream(fastUrl.openConnection().getInputStream());
> + String slowUrlContent = getContentOfStream(slowUrl.openConnection().getInputStream());
> + Assert.assertEquals(fastUrlcontent, slowUrlContent);
> +
> }
>
> /**
> @@ -789,6 +827,7 @@
> private final File dir;
> private final int port;
> private boolean canRun = true;
> + private static final String XSX="/XslowX";
>
> public void setCanRun(boolean canRun) {
> this.canRun = canRun;
> @@ -819,7 +858,9 @@
> if (s.startsWith("GET")) {
> StringTokenizer t = new StringTokenizer(s, " ");
> t.nextToken();
> - String p = t.nextToken();
> + String op = t.nextToken();
> + String p = op;
> + if (p.startsWith(XSX))p=p.replace(XSX, "/");
> System.err.println("Getting: "+p);
> p=URLDecoder.decode(p, "UTF-8");
> System.err.println("Serving: "+p);
> @@ -832,9 +873,20 @@
> f.read(b);
> o.writeBytes("HTTP/1.0 200 OK\nConten"
> + "t-Length:" + l + "\n\n");
> + if (op.startsWith(XSX)){
> + byte[][] bb=ServerAccess.splitArray(b,10);
> + for (int j = 0; j < bb.length; j++) {
> + Thread.sleep(2000);
> + byte[] bs = bb[j];
> + o.write(bs, 0, bs.length);
> + }
> + }else{
> o.write(b, 0, l);
> + }
> }
> }
> + }catch (SocketException e) {
> + e.printStackTrace();
> } catch (Exception e) {
> o.writeBytes("HTTP/1.0 404 ERROR\n\n\n");
> e.printStackTrace();
> @@ -847,6 +899,89 @@
> }
> }
>
> + private static byte[][] splitArray(byte[] b, int i) {
> +
> + byte[][] r=new byte[i][0];
> + int ln=b.length % (i);
> + int l1=(b.length) / (i);
> + if (ln==0){
> + ln=l1;
> + }else{
> + l1=l1+1;
> + ln=b.length%l1;;
> + }
> + for (int j = 0; j < r.length; j++) {
> + if (j==r.length-1){
> + r[j]=new byte[ln];
> + }else{
> + r[j]=new byte[l1];
> + }
> + byte[] q=r[j];
> + for (int x=0; x< q.length;x++){
> + q[x]=b[x+l1*j];
> + }
> +
> +
> + }
> + return r;
> + }
> +
> + @Test
> + public void splitArrayTest0() throws Exception {
> + byte[] b={1,2,3,4,5,6,7,8,9,10,11,12,13,14};
> + byte[][] bb=splitArray(b, 3);
> + //printArrays(bb);
> + byte[] b1={1,2,3,4,5};
> + byte[] b2={6,7,8,9,10};
> + byte[] b3={11,12,13,14};
> + Assert.assertEquals(3,bb.length);
> + Assert.assertArrayEquals(b1,bb[0]);
> + Assert.assertArrayEquals(b2,bb[1]);
> + Assert.assertArrayEquals(b3,bb[2]);
> + }
> +
> + @Test
> + public void splitArrayTest1() throws Exception {
> + byte[] b={1,2,3,4,5,6,7,8,9,10,11,12,13};
> + byte[][] bb=splitArray(b, 3);
> + //printArrays(bb);
> + byte[] b1={1,2,3,4,5};
> + byte[] b2={6,7,8,9,10};
> + byte[] b3={11,12,13};
> + Assert.assertEquals(3,bb.length);
> + Assert.assertArrayEquals(b1,bb[0]);
> + Assert.assertArrayEquals(b2,bb[1]);
> + Assert.assertArrayEquals(b3,bb[2]);
> + }
> +
> + @Test
> + public void splitArrayTest2() throws Exception {
> + byte[] b={1,2,3,4,5,6,7,8,9,10,11,12};
> + byte[][] bb=splitArray(b, 3);
> + //printArrays(bb);
> + byte[] b1={1,2,3,4};
> + byte[] b2={5,6,7,8};
> + byte[] b3={9,10,11,12};
> + Assert.assertEquals(3,bb.length);
> + Assert.assertArrayEquals(b1,bb[0]);
> + Assert.assertArrayEquals(b2,bb[1]);
> + Assert.assertArrayEquals(b3,bb[2]);
> + }
> +
> + private void printArrays(byte[][] bb) {
> + System.out.println("[][] l=" + bb.length);
> + for (int i = 0; i < bb.length; i++) {
> + byte[] bs = bb[i];
> + System.out.println(i + ": l=" + bs.length);
> + for (int j = 0; j < bs.length; j++) {
> + byte c = bs[j];
> + System.out.print(" " + j + ":" + c + " ");
> + }
> + System.out.println("");
> + }
> + }
> +
> +
> /**
> * class which timeout any ThreadedProcess. This killing of 'theread with process' replaced not working process.destroy().
> */
> Resultant of Forces
> (Addition of Vectors)
>
> Resultant of Forces
> (Addition of Vectors)
> #!/bin/bash
>
> JAVA=/usr/lib/jvm/java-openjdk/jre/bin/java
> LAUNCHER_BOOTCLASSPATH="-Xbootclasspath/a:/home/jvanek/icedtea-web-image/share/icedtea-web/netx.jar:/usr/share/java/js.jar"
> LAUNCHER_FLAGS=-Xms8m
> CLASSNAME=net.sourceforge.jnlp.runtime.Boot
> BINARY_LOCATION=/home/jvanek/icedtea-web-image/bin/javaws
> PROGRAM_NAME=javaws
> CP=/usr/lib/jvm/java-openjdk/jre/lib/rt.jar
>
> JAVA_ARGS=( )
> ARGS=( )
> COMMAND=()
>
> i=0
> j=0
>
> SPLASH="true"
> while [ "$#" -gt "0" ]; do
> case "$1" in
> -J*)
> JAVA_ARGS[$i]="${1##-J}"
> i=$((i+1))
> ;;
> *)
> ARGS[$j]="$1"
> j=$((j+1))
> if [ "$1" = "-headless" ] ; then
> SPLASH="false"
> fi
> ;;
> esac
> shift
> done
>
> k=0
> COMMAND[k]="${JAVA}"
> k=$((k+1))
> if [ "$SPLASH" = "true" ] ; then
> COMMAND[k]="-splash:/home/jvanek/icedtea-web-image/bin/netxPlugin.png"
> k=$((k+1))
> fi;
> COMMAND[k]="${LAUNCHER_BOOTCLASSPATH}"
> k=$((k+1))
> COMMAND[k]="${LAUNCHER_FLAGS}"
> k=$((k+1))
> i=0
> while [ "$i" -lt "${#JAVA_ARGS[@]}" ]; do
> COMMAND[k]="${JAVA_ARGS[$i]}"
> i=$((i+1))
> k=$((k+1))
> done
> COMMAND[k]="-classpath"
> k=$((k+1))
> COMMAND[k]="${CP}"
> k=$((k+1))
> COMMAND[k]="-Dicedtea-web.bin.name=${PROGRAM_NAME}"
> k=$((k+1))
> COMMAND[k]="-Dicedtea-web.bin.location=${BINARY_LOCATION}"
> k=$((k+1))
> COMMAND[k]="${CLASSNAME}"
> k=$((k+1))
> j=0
> while [ "$j" -lt "${#ARGS[@]}" ]; do
> COMMAND[k]="${ARGS[$j]}"
> j=$((j+1))
> k=$((k+1))
> done
>
> "${COMMAND[@]}"
>
> exit $?
More information about the distro-pkg-dev
mailing list