Package freenet.node.updater

Source Code of freenet.node.updater.PluginJarUpdater

package freenet.node.updater;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import freenet.client.FetchResult;
import freenet.clients.http.PproxyToadlet;
import freenet.keys.FreenetURI;
import freenet.l10n.NodeL10n;
import freenet.node.RequestClient;
import freenet.node.Version;
import freenet.node.useralerts.AbstractUserAlert;
import freenet.node.useralerts.UserAlert;
import freenet.pluginmanager.PluginInfoWrapper;
import freenet.pluginmanager.PluginManager;
import freenet.support.HTMLNode;
import freenet.support.Logger;
import freenet.support.api.Bucket;
import freenet.support.io.BucketTools;

public class PluginJarUpdater extends NodeUpdater {

  final String pluginName;
  final PluginManager pluginManager;
  private UserAlert alert;
  private boolean deployOnNoRevocation;
  private boolean deployOnNextNoRevocation;
  private boolean readyToDeploy;
  private FetchResult result;
 
  private final Object writeJarSync = new Object();
  private int writtenVersion;

  /**
   * @return True if the caller should restart the revocation checker.
   */
  boolean onNoRevocation() {
    synchronized(this) {
      if(!readyToDeploy) return false;
      if(deployOnNoRevocation) {
        // Lets go ...
      } else if(deployOnNextNoRevocation) {
        deployOnNoRevocation = true;
        deployOnNextNoRevocation = false;
        System.out.println("Deploying "+pluginName+" after next revocation check");
        return true;
      } else
        return false;
    }
    // Deploy it!
    if (!pluginManager.isPluginLoaded(pluginName)) {
      Logger.error(this, "Plugin is not loaded, so not deploying: "+pluginName);
      tempBlobFile.delete();
      return false;
    }
    System.out.println("Deploying new version of "+pluginName+" : unloading old version...");
    // Write the new version of the plugin before shutting down, so if there is a deadlock in terminate, we will still get the new version after a restart.
    try {
      writeJar();
    } catch (IOException e) {
      Logger.error(this, "Cannot deploy: "+e, e);
      System.err.println("Cannot deploy new version of "+pluginName+" : "+e);
      e.printStackTrace();
      return false; // Not much we can do ...
      // FIXME post a useralert
    }
    pluginManager.killPluginByFilename(pluginName, Integer.MAX_VALUE, true);
    pluginManager.startPluginAuto(pluginName, true);
    UserAlert a;
    synchronized(this) {
      a = alert;
      alert = null;
    }
    node.clientCore.alerts.unregister(a);
    return false;
  }
 
  PluginJarUpdater(NodeUpdateManager manager, FreenetURI URI, int current, int min, int max, String blobFilenamePrefix, String pluginName, PluginManager pm, boolean autoDeployOnRestart) {
    super(manager, URI, current, min, max, blobFilenamePrefix);
    this.pluginName = pluginName;
    this.pluginManager = pm;
  }

  @Override
  public String jarName() {
    return pluginName;
  }

  private int requiredNodeVersion;
 
  private static final String REQUIRED_NODE_VERSION_PREFIX = "Required-Node-Version: ";
 
  @Override
  protected void maybeParseManifest(FetchResult result, int build) {
    requiredNodeVersion = -1;
    parseManifest(result);
    if(requiredNodeVersion != -1) {
      System.err.println("Required node version for plugin "+pluginName+": "+requiredNodeVersion);
      Logger.normal(this, "Required node version for plugin "+pluginName+": "+requiredNodeVersion);
    }
  }
 
  @Override
  protected void parseManifestLine(String line) {
    if(line.startsWith(REQUIRED_NODE_VERSION_PREFIX)) {
      requiredNodeVersion = Integer.parseInt(line.substring(REQUIRED_NODE_VERSION_PREFIX.length()));
    }
  }
 
  @Override
  protected void onStartFetching() {
    System.err.println("Starting to fetch plugin "+pluginName);
  }

  @Override
  protected void processSuccess(int build, FetchResult result, File blob) {
    Bucket oldResult = null;
    synchronized(this) {
      if(requiredNodeVersion > Version.buildNumber()) {
        System.err.println("Found version "+fetchedVersion+" of "+pluginName+" but needs node version "+requiredNodeVersion);
        // FIXME deploy it with the main jar
        tempBlobFile.delete();
        return;
      }
      if(this.result != null)
        oldResult = this.result.asBucket();
      this.result = result;
    }
    if(oldResult != null) oldResult.free();
   
    PluginInfoWrapper loaded = pluginManager.getPluginInfo(pluginName);
   
    if(loaded == null) {
      if(!node.pluginManager.isPluginLoadedOrLoadingOrWantLoad(pluginName)) {
        System.err.println("Don't want plugin: "+pluginName);
        Logger.error(this, "Don't want plugin: "+pluginName);
        tempBlobFile.delete();
        return;
      }
    }
   
    if(loaded.getPluginLongVersion() >= fetchedVersion) {
      tempBlobFile.delete();
      return;
    }
    // Create a useralert to ask the user to deploy the new version.
   
    UserAlert toRegister = null;
    synchronized(this) {
      readyToDeploy = true;
      if(alert != null) return;
     
      toRegister = alert = new AbstractUserAlert(true, l10n("pluginUpdatedTitle", "name", pluginName), l10n("pluginUpdatedText", "name", pluginName), l10n("pluginUpdatedShortText", "name", pluginName), null, UserAlert.ERROR, true, NodeL10n.getBase().getString("UserAlert.hide"), true, this) {
       
        @Override
        public void onDismiss() {
          synchronized(PluginJarUpdater.this) {
            alert = null;
          }
        }
       
        @Override
        public HTMLNode getHTMLText() {
          HTMLNode div = new HTMLNode("div");
          // Text saying the plugin has been updated...
          synchronized(this) {
         
            if(deployOnNoRevocation || deployOnNextNoRevocation) {
              div.addChild("#", l10n("willDeployAfterRevocationCheck", "name", pluginName));
            } else {
              div.addChild("#", l10n("pluginUpdatedText", new String[] { "name", "newVersion" }, new String[] { pluginName, Long.toString(fetchedVersion) }));
             
              // Form to deploy the updated version.
              // This is not the same as reloading because we haven't written it yet.
             
              HTMLNode formNode = div.addChild("form", new String[] { "action", "method" }, new String[] { PproxyToadlet.PATH, "post" });
              formNode.addChild("input", new String[] { "type", "name", "value" }, new String[] { "hidden", "formPassword", node.clientCore.formPassword });
              formNode.addChild("input", new String[] { "type", "name", "value" }, new String[] { "hidden", "update", pluginName });
              formNode.addChild("input", new String[] { "type", "value" }, new String[] { "submit", l10n("updatePlugin") });
            }
          }
          return div;
        }
      };
    }
    if(toRegister != null)
      node.clientCore.alerts.register(toRegister);
  }

  private String l10n(String key) {
    return NodeL10n.getBase().getString("PluginJarUpdater."+key);
  }

  private String l10n(String key, String name, String value) {
    return NodeL10n.getBase().getString("PluginJarUpdater."+key, name, value);
  }

  private String l10n(String key, String[] names, String[] values) {
    return NodeL10n.getBase().getString("PluginJarUpdater."+key, names, values);
  }
 
  public void writeJarTo(FetchResult result, File fNew) throws IOException {
    int fetched;
    synchronized(this) {
      fetched = fetchedVersion;
    }
    synchronized(writeJarSync) {
      if (!fNew.delete() && fNew.exists()) {
        System.err.println("Can't delete " + fNew + "!");
      }

      FileOutputStream fos;
      fos = new FileOutputStream(fNew);

      BucketTools.copyTo(result.asBucket(), fos, -1);

      fos.flush();
      fos.close();
    }
    synchronized(this) {
      writtenVersion = fetched;
    }
    System.err.println("Written " + jarName() + " to " + fNew);
  }

  void writeJar() throws IOException {
    writeJarTo(result, pluginManager.getPluginFilename(pluginName));
    UserAlert a;
    synchronized(this) {
      a = alert;
      alert = null;
    }
    if(a != null)
      node.clientCore.alerts.unregister(a);
  }

  @Override
  void kill() {
    super.kill();
    UserAlert a;
    synchronized(this) {
      a = alert;
      alert = null;
    }
    if(a != null)
      node.clientCore.alerts.unregister(a);
  }

  public synchronized void arm(boolean wasRunning) {
    if(wasRunning) {
      deployOnNextNoRevocation = true;
      System.out.println("Deploying "+pluginName+" after next but one revocation check");
    } else {
      deployOnNoRevocation = true;
      System.out.println("Deploying "+pluginName+" after next revocation check");
    }
  }

  @Override
  public RequestClient getRequestClient() {
    return pluginManager.singleUpdaterRequestClient;
  }
 
}
TOP

Related Classes of freenet.node.updater.PluginJarUpdater

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.