All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.caucho.server.deploy.DeployActor Maven / Gradle / Ivy

/*
 * Copyright (c) 1998-2018 Caucho Technology -- all rights reserved
 *
 * This file is part of Resin(R) Open Source
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Resin Open Source is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Resin Open Source is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Resin Open Source; if not, write to the
 *
 *   Free Software Foundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Scott Ferguson
 */

package com.caucho.server.deploy;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;

import com.caucho.bam.broker.Broker;
import com.caucho.bam.mailbox.Mailbox;
import com.caucho.bam.manager.BamManager;
import com.caucho.bam.proxy.ActorFor;
import com.caucho.bam.proxy.ReplyCallback;
import com.caucho.cloud.bam.BamSystem;
import com.caucho.config.ConfigException;
import com.caucho.env.deploy.DeployControllerService;
import com.caucho.env.deploy.DeployException;
import com.caucho.env.deploy.DeployTagItem;
import com.caucho.env.git.GitTree;
import com.caucho.env.repository.RepositorySpi;
import com.caucho.env.repository.RepositorySystem;
import com.caucho.env.repository.RepositoryTagEntry;
import com.caucho.env.service.ResinSystem;
import com.caucho.env.thread.ThreadPool;
import com.caucho.lifecycle.LifecycleState;
import com.caucho.util.IoUtil;
import com.caucho.util.L10N;
import com.caucho.vfs.StreamSource;

@ActorFor(api = DeployActorProxy.class)
public class DeployActor
{
  private static final L10N L = new L10N(DeployActor.class);
  
  private static final Logger log
    = Logger.getLogger(DeployActor.class.getName());
  
  private static final String UID = "deploy";
  public static final String ADDRESS = UID + '@' + "resin.caucho";
  
  private String _serverId;
  private RepositorySpi _repository;
  
  private final AtomicBoolean _isInit = new AtomicBoolean();

  public DeployActor()
  {
    _serverId = ResinSystem.getCurrentId();
  }

  public void init()
  {
    if (_isInit.getAndSet(true))
      return;

    _repository = RepositorySystem.getCurrentRepositorySpi();

    Broker broker = BamSystem.getCurrentBroker();
    BamManager bamManager = BamSystem.getCurrentManager();
    
    Mailbox mailbox = bamManager.createService(ADDRESS, this);
    
    String proxyAddress = UID + '@' + broker.getAddress();
    bamManager.addMailbox(proxyAddress, mailbox);
  }

  
  public String []getCommitList(String []commitList)
  {
    ArrayList uncommittedList = new ArrayList();
    
    if (commitList != null) {
      for (String commit : commitList) {
        if (! _repository.exists(commit))
          uncommittedList.add(commit);
      }
    }
    
    String []result = new String[uncommittedList.size()];
    uncommittedList.toArray(result);

    return result;
  }

  /**
   * Returns a file to the client.
   */
  public StreamSource getFile(String tag, String fileName)
    throws IOException
  {
    if (log.isLoggable(Level.FINER)) {
      log.finer(this + " getFile(" + tag + "," + fileName + ")");
    }
    
    while (fileName.startsWith("/")) {
      fileName = fileName.substring(1);
    }
    
    RepositoryTagEntry entry = _repository.getTagMap().get(tag);
    
    if (entry == null) {
      throw new ConfigException(L.l("'{0}' is an unknown repository tag",
                                    tag));
    }
    
    String sha1 = entry.getRoot();
    
    String fileSha = findFile(sha1, fileName, fileName);

    BlobStreamSource iss = new BlobStreamSource(_repository, fileSha);
    
    return new StreamSource(iss);
  }
  
  private String findFile(String sha1, String fullFilename, String fileName)
    throws IOException
  {
    if (fileName.equals("")) {
      if (_repository.isBlob(sha1))
        return sha1;
      else {
        throw new ConfigException(L.l("'{0}' is not a file", fullFilename));
      }
    }
    
    int p = fileName.indexOf('/');
    String tail = "";
    
    if (p > 0) {
      tail = fileName.substring(p + 1);
      fileName = fileName.substring(0, p);
    }
    
    if (! _repository.isTree(sha1))
      throw new ConfigException(L.l("'{0}' is an invalid path", fullFilename));
    
    GitTree tree = _repository.readTree(sha1);
    
    String childSha1 = tree.getHash(fileName);
    
    if (childSha1 == null)
      throw new ConfigException(L.l("'{0}' is an unknown file",
                                    fullFilename));
   
    return findFile(childSha1, fullFilename, tail);
  }

  /**
   * Receives a file from the client.
   * 
   * @param sha1 the hash identifier for the file
   * @param source the binary stream content
   */
  public boolean sendFile(String sha1, StreamSource source)
  {
    if (log.isLoggable(Level.FINER))
      log.finer(this + " sendFile sha1=" + sha1);

    InputStream is = null;
    try {
      is = source.getInputStream();

      _repository.writeRawGitFile(sha1, is);
    } catch (Exception e) {
      log.log(Level.WARNING, e.toString(), e);

      return false;
    } finally {
      IoUtil.close(is);
    }

    return true;
  }

  public String []listFiles(String tag, String fileName)
    throws IOException
  {
    if (log.isLoggable(Level.FINER)) {
      log.finer(this + " getFileList(" + tag + "," + fileName + ")");
    }
    
    RepositoryTagEntry entry = _repository.getTagMap().get(tag);
    
    if (entry == null) {
      throw new ConfigException(L.l("'{0}' is an unknown repository tag",
                                    tag));
    }
    
    String sha1 = entry.getRoot();
    
    ArrayList fileList = new ArrayList();
    
    listFiles(fileList, sha1, "");
    
    Collections.sort(fileList);
    
    String []files = new String[fileList.size()];
    
    fileList.toArray(files);

    return files;
  }
  
  private void listFiles(ArrayList files, 
                         String sha1,
                         String prefix)
    throws IOException
  {
    if (sha1 == null)
      return;
    
    if (_repository.isBlob(sha1)) {
      files.add(prefix);
      return;
    }
    
    if (! _repository.isTree(sha1))
      throw new ConfigException(L.l("'{0}' is an invalid path", prefix));
    
    GitTree tree = _repository.readTree(sha1);
    
    for (String key : tree.getMap().keySet()) {
      String name;
      
      if ("".equals(prefix))
        name = key;
      else
        name = prefix + "/" + key;
      
      listFiles(files, tree.getHash(key), name);
    }
  }
  
  //
  // tag methods
  //

  public boolean putTag(String tagName, 
                        String contentHash,
                        Map attributes)
  {
    if (contentHash == null)
      throw new NullPointerException();

    String server = "default";
    
    TreeMap commitMetaData = new TreeMap();
    
    if (attributes != null) {
      commitMetaData.putAll(attributes);
    }
    
    commitMetaData.put("server", server);
    
    return _repository.putTag(tagName, 
                              contentHash,
                              commitMetaData);
  }

  public boolean copyTag(String tag, 
                         String sourceTag, 
                         Map attributes)
  {
    RepositoryTagEntry entry = _repository.getTagMap().get(sourceTag);

    if (entry == null) {
      log.fine(this + " copyError dst='" + tag + "' src='" + sourceTag + "'");

      throw new DeployException(L.l("deploy-copy: '{0}' is an unknown source tag.",
                                    sourceTag));
    }

    log.fine(this + " copy dst='" + tag + "' src='" + sourceTag + "'");
    
    String server = "default";
    
    TreeMap metaDataMap = new TreeMap();
    
    if (attributes != null)
      metaDataMap.putAll(attributes);
    
    if (server != null)
      metaDataMap.put("server", server);

    return _repository.putTag(tag, entry.getRoot(), metaDataMap);
  }

  public DeployTagResult []queryTags(String regexp)
  {
    ArrayList tags = new ArrayList();

    Pattern pattern = Pattern.compile(regexp);

    for (Map.Entry entry
          :  _repository.getTagMap().entrySet()) {
      String tag = entry.getKey();

      if (pattern.matcher(tag).find()) {
        tags.add(new DeployTagResult(tag, entry.getValue().getRoot()));
      }
    }

    return tags.toArray(new DeployTagResult[tags.size()]);
  }

  public DeployTagStateQuery getTagState(String tag)
  {
    // XXX: just ping the tag?
    // updateDeploy();
    
    DeployControllerService deploy = DeployControllerService.getCurrent();
    DeployTagItem item = null;
    
    if (deploy != null) {
      deploy.update(tag);
      item = deploy.getTagItem(tag);
    }
    
    if (item != null) {
      return new DeployTagStateQuery(tag, item.getStateName(),
                               item.getDeployException());
    }
    else {
      return null;
    }
  }

  public boolean removeTag(String tag, Map attributes)
  {
    if (log.isLoggable(Level.FINE))
      log.fine(this + " removeTag " + tag);
    
    String server = "default";
    
    HashMap commitMetaData = new HashMap();
    
    if (attributes != null) {
      commitMetaData.putAll(attributes);
    }
    
    commitMetaData.put("server", server);

    return _repository.removeTag(tag, commitMetaData);
  }

  //
  // start/restart
  //

  public DeployControllerState start(String tag)
  {
    LifecycleState state = startImpl(tag);

    DeployControllerState result
      = new DeployControllerState(tag, state);

    log.fine(this
             + " start '"
             + tag
             + "' -> "
             + state.getStateName());

    return result;
  }

  private LifecycleState startImpl(String tag)
  {
    DeployControllerService service = DeployControllerService.getCurrent();
    
    DeployTagItem controller = service.getTagItem(tag);

    if (controller == null)
      throw new IllegalArgumentException(L.l("'{0}' is an unknown controller",
                                             tag));

    controller.toStart();

    return controller.getState();
  }

  /**
   * @deprecated
   */
  public DeployControllerState stop(String tag)
  {
    LifecycleState state = stopImpl(tag);

    log.fine(this + " stop '" + tag + "' -> " + state.getStateName());

    return new DeployControllerState(tag, state);
  }

  private LifecycleState stopImpl(String tag)
  {
    DeployControllerService service = DeployControllerService.getCurrent();

    DeployTagItem controller = service.getTagItem(tag);

    if (controller == null)
      throw new IllegalArgumentException(L.l("'{0}' is an unknown controller",
                                             tag));
    controller.toStop();

    //windows WEB-INF/lib/*.jar release for eclipse-plugin's web-app-stop
    System.gc();

    return controller.getState();
  }

  public void controllerRestart(String tag,
                                ReplyCallback cb)
  {
    restart(tag, cb);
  }

  public void restart(String tag,
                      ReplyCallback cb)
  {
    restartImpl(tag, cb);
    /*
    LifecycleState state = restartImpl(tag);

    DeployControllerState result
      = new DeployControllerState(tag, state);

    log.fine(this
             + " restart '"
             + tag
             + "' -> "
             + state.getStateName());

    return result;
    */
  }

  public void restartCluster(String tag,
                             ReplyCallback cb)
  {
    throw new UnsupportedOperationException(getClass().getName());
  }

  private void restartImpl(final String tag,
                           final ReplyCallback cb)
  {
    DeployControllerService service = DeployControllerService.getCurrent();

    final DeployTagItem controller = service.getTagItem(tag);

    if (controller == null)
      throw new IllegalArgumentException(L.l("'{0}' is an unknown controller",
                                             tag));

    ThreadPool.getCurrent().schedule(new Runnable() {
      @Override
      public void run() {
        try {
          controller.toRestart();
        } finally {
          cb.onReply(new DeployControllerState(tag, controller.getState()));
        }
      }
    });

    // return controller.getState();
  }
  
  public String getUid()
  {
    return UID;
  }
  
  @Override
  public String toString()
  {
    return getClass().getSimpleName() + "[" + _serverId + "]";
  }
  
  static class BlobStreamSource extends StreamSource {
    private RepositorySpi _repository;
    private String _sha1;
    
    BlobStreamSource(RepositorySpi repository, String sha1)
    {
      _repository = repository;
      _sha1 = sha1;
    }
    
    /**
     * Returns an input stream, freeing the results
     */
    @Override
    public InputStream getInputStream()
      throws IOException
    {
        return _repository.openRawGitFile(_sha1);
    }

    /**
     * Returns an input stream, without freeing the results
     */
    @Override
    public InputStream openInputStream()
      throws IOException
    {
      return _repository.openRawGitFile(_sha1);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy