Package org.apache.ambari.server.view

Source Code of org.apache.ambari.server.view.ViewRegistry

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.ambari.server.view;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import org.apache.ambari.server.api.resources.ResourceInstanceFactoryImpl;
import org.apache.ambari.server.api.resources.SubResourceDefinition;
import org.apache.ambari.server.api.resources.ViewExternalSubResourceDefinition;
import org.apache.ambari.server.api.services.ViewExternalSubResourceService;
import org.apache.ambari.server.api.services.ViewSubResourceService;
import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.controller.spi.Resource;
import org.apache.ambari.server.orm.dao.ViewDAO;
import org.apache.ambari.server.orm.dao.ViewInstanceDAO;
import org.apache.ambari.server.orm.entities.ViewEntity;
import org.apache.ambari.server.orm.entities.ViewEntityEntity;
import org.apache.ambari.server.orm.entities.ViewInstanceDataEntity;
import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
import org.apache.ambari.server.orm.entities.ViewParameterEntity;
import org.apache.ambari.server.orm.entities.ViewResourceEntity;
import org.apache.ambari.server.view.configuration.EntityConfig;
import org.apache.ambari.server.view.configuration.InstanceConfig;
import org.apache.ambari.server.view.configuration.ParameterConfig;
import org.apache.ambari.server.view.configuration.PersistenceConfig;
import org.apache.ambari.server.view.configuration.PropertyConfig;
import org.apache.ambari.server.view.configuration.ResourceConfig;
import org.apache.ambari.server.view.configuration.ViewConfig;
import org.apache.ambari.view.SystemException;
import org.apache.ambari.view.View;
import org.apache.ambari.view.ViewContext;
import org.apache.ambari.view.ViewDefinition;
import org.apache.ambari.view.ViewResourceHandler;
import org.apache.ambari.view.events.Event;
import org.apache.ambari.view.events.Listener;
import org.eclipse.jetty.webapp.WebAppContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.beans.IntrospectionException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
* Registry for view and view instance definitions.
*/
public class ViewRegistry {

  /**
   * Constants
   */
  private static final String VIEW_XML = "view.xml";
  private static final String ARCHIVE_CLASSES_DIR = "WEB-INF/classes";
  private static final String ARCHIVE_LIB_DIR = "WEB-INF/lib";
  private static final String EXTRACTED_ARCHIVES_DIR = "work";

  /**
   * Mapping of view names to view definitions.
   */
  private Map<String, ViewEntity> viewDefinitions = new HashMap<String, ViewEntity>();

  /**
   * Mapping of view instances to view definition and instance name.
   */
  private Map<ViewEntity, Map<String, ViewInstanceEntity>> viewInstanceDefinitions =
      new HashMap<ViewEntity, Map<String, ViewInstanceEntity>>();

  /**
   * Mapping of view names to sub-resources.
   */
  private final Map<String, Set<SubResourceDefinition>> subResourceDefinitionsMap =
      new HashMap<String, Set<SubResourceDefinition>>();

  /**
   * Mapping of view names to registered listeners.
   */
  private final Map<String, List<Listener>> listeners =
      new HashMap<String, List<Listener>>();

  /**
   * Helper class.
   */
  private ViewRegistryHelper helper = new ViewRegistryHelper();

  /**
   * The singleton view registry instance.
   */
  private static final ViewRegistry singleton = new ViewRegistry();

  /**
   * The logger.
   */
  protected final static Logger LOG = LoggerFactory.getLogger(ViewRegistry.class);

  /**
   * View data access object.
   */
  private static ViewDAO viewDAO;

  /**
   * View instance data access object.
   */
  private static ViewInstanceDAO instanceDAO;


  // ----- Constructors ------------------------------------------------------

  /**
   * Hide the constructor for this singleton.
   */
  private ViewRegistry() {
  }


  // ----- ViewRegistry ------------------------------------------------------

  /**
   * Get the collection of all the view definitions.
   *
   * @return the collection of view definitions
   */
  public Collection<ViewEntity> getDefinitions() {
    return viewDefinitions.values();
  }

  /**
   * Get a view definition for the given name.
   *
   * @param viewName  the view name
   * @param version   the version
   *
   * @return the view definition for the given name
   */
  public ViewEntity getDefinition(String viewName, String version) {
    return getDefinition(ViewEntity.getViewName(viewName, version));
  }

  /**
   * Add a view definition to the registry.
   *
   * @param definition  the definition
   */
  public void addDefinition(ViewEntity definition) {
    View view = definition.getView();
    if (view != null) {
      view.onDeploy(definition);
    }
    viewDefinitions.put(definition.getName(), definition);
  }

  /**
   * Get the collection of view instances for the given view definition.
   *
   * @param definition  the view definition
   *
   * @return the collection of view instances for the view definition
   */
  public Collection<ViewInstanceEntity> getInstanceDefinitions(ViewEntity definition) {
    if (definition != null) {
      Map<String, ViewInstanceEntity> instanceEntityMap = viewInstanceDefinitions.get(definition);
      if (instanceEntityMap != null) {
        return instanceEntityMap.values();
      }
    }
    return Collections.emptyList();
  }

  /**
   * Get the instance definition for the given view nam,e and instance name.
   *
   * @param viewName      the view name
   * @param version       the version
   * @param instanceName  the instance name
   *
   * @return the view instance definition for the given view and instance name
   */
  public ViewInstanceEntity getInstanceDefinition(String viewName, String version, String instanceName) {
    Map<String, ViewInstanceEntity> viewInstanceDefinitionMap =
        viewInstanceDefinitions.get(getDefinition(viewName, version));

    return viewInstanceDefinitionMap == null ? null : viewInstanceDefinitionMap.get(instanceName);
  }

  /**
   * Add an instance definition for the given view definition.
   *
   * @param definition          the owning view definition
   * @param instanceDefinition  the instance definition
   */
  public void addInstanceDefinition(ViewEntity definition, ViewInstanceEntity instanceDefinition) {
    Map<String, ViewInstanceEntity> instanceDefinitions = viewInstanceDefinitions.get(definition);
    if (instanceDefinitions == null) {
      instanceDefinitions = new HashMap<String, ViewInstanceEntity>();
      viewInstanceDefinitions.put(definition, instanceDefinitions);
    }

    View view = definition.getView();
    if (view != null) {
      view.onCreate(instanceDefinition);
    }
    instanceDefinitions.put(instanceDefinition.getName(), instanceDefinition);
  }

  /**
   * Remove an instance definition for the given view definition.
   *
   * @param definition    the owning view definition
   * @param instanceName  the instance name
   */
  public void removeInstanceDefinition(ViewEntity definition, String instanceName) {
    Map<String, ViewInstanceEntity> instanceDefinitions = viewInstanceDefinitions.get(definition);
    if (instanceDefinitions != null) {

      ViewInstanceEntity instanceDefinition = instanceDefinitions.get(instanceName);
      if (instanceDefinition != null) {
        View view = definition.getView();
        if (view != null) {
          view.onDestroy(instanceDefinition);
        }
        instanceDefinitions.remove(instanceName);
      }
    }
  }

  /**
   * Get the view registry singleton.
   *
   * @return  the view registry
   */
  public static ViewRegistry getInstance() {
    return singleton;
  }

  /**
   * Get the sub-resource definitions for the given view name.
   *
   * @param viewName  the instance name
   * @param version   the version
   *
   * @return the set of sub-resource definitions
   */
  public synchronized Set<SubResourceDefinition> getSubResourceDefinitions(
      String viewName, String version) {

    viewName = ViewEntity.getViewName(viewName, version);

    Set<SubResourceDefinition> subResourceDefinitions =
        subResourceDefinitionsMap.get(viewName);

    if (subResourceDefinitions == null) {
      subResourceDefinitions = new HashSet<SubResourceDefinition>();
      ViewEntity definition = getDefinition(viewName);
      if (definition != null) {
        for (Resource.Type type : definition.getViewResourceTypes()) {
          subResourceDefinitions.add(new SubResourceDefinition(type));
        }
      }
      subResourceDefinitionsMap.put(viewName, subResourceDefinitions);
    }
    return subResourceDefinitions;
  }

  /**
   * Read the view archives.
   *
   * @param configuration  Ambari configuration
   *
   * @return the set of view instance definitions read from the archives
   *
   * @throws SystemException if the view archives can not be successfully read
   */
  public Set<ViewInstanceEntity> readViewArchives(Configuration configuration)
      throws SystemException {

    try {
      File viewDir = configuration.getViewsDir();

      Set<ViewInstanceEntity> allInstanceDefinitions = new HashSet<ViewInstanceEntity>();

      String extractedArchivesPath = viewDir.getAbsolutePath() +
          File.separator + EXTRACTED_ARCHIVES_DIR;

      if (ensureExtractedArchiveDirectory(extractedArchivesPath)) {
        File[] files = viewDir.listFiles();

        if (files != null) {
          for (File archiveFile : files) {
            if (!archiveFile.isDirectory()) {
              try {
                ViewConfig viewConfig = helper.getViewConfigFromArchive(archiveFile);

                String viewName    = ViewEntity.getViewName(viewConfig.getName(), viewConfig.getVersion());
                String archivePath = extractedArchivesPath + File.separator + viewName;

                // extract the archive and get the class loader
                ClassLoader cl = extractViewArchive(archiveFile, helper.getFile(archivePath));

                ViewEntity viewDefinition = createViewDefinition(viewConfig, configuration, cl, archivePath);

                Set<ViewInstanceEntity> instanceDefinitions = new HashSet<ViewInstanceEntity>();

                for (InstanceConfig instanceConfig : viewConfig.getInstances()) {
                  try {
                    instanceDefinitions.add(createViewInstanceDefinition(viewDefinition, instanceConfig));
                  } catch (Exception e) {
                    LOG.error("Caught exception adding view instance for view " +
                        viewDefinition.getViewName(), e);
                  }
                }
                // ensure that the view entity matches the db
                syncView(viewDefinition, instanceDefinitions);

                // update the registry with the view
                addDefinition(viewDefinition);

                // update the registry with the view instances
                for (ViewInstanceEntity instanceEntity : instanceDefinitions) {
                  addInstanceDefinition(viewDefinition, instanceEntity);
                }

                allInstanceDefinitions.addAll(instanceDefinitions);
              } catch (Exception e) {
                LOG.error("Caught exception loading view from " + archiveFile.getAbsolutePath(), e);
              }
            }
          }
          removeUndeployedViews();
        }
      }
      return allInstanceDefinitions;
    } catch (Exception e) {
      throw new SystemException("Caught exception reading view archives.", e);
    }
  }

  /**
   * Install the given view instance with its associated view.
   *
   * @param instanceEntity  the view instance entity
   *
   * @throws IllegalStateException     if the given instance is not in a valid state
   * @throws IllegalArgumentException  if the view associated with the given instance
   *                                   does not exist
   */
  public void installViewInstance(ViewInstanceEntity instanceEntity)
      throws IllegalStateException, IllegalArgumentException {
    ViewEntity viewEntity = getDefinition(instanceEntity.getViewName());

    if (viewEntity != null) {
      String instanceName = instanceEntity.getName();
      String viewName     = viewEntity.getCommonName();
      String version      = viewEntity.getVersion();

      if (getInstanceDefinition(viewName, version, instanceName) == null) {
        if (LOG.isDebugEnabled()) {
          LOG.debug("Creating view instance " + viewName + "/" +
              version + "/" + instanceName);
        }
        instanceEntity.validate(viewEntity);
        instanceDAO.merge(instanceEntity);

        ViewInstanceEntity persistedInstance = instanceDAO.findByName(ViewEntity.getViewName(viewName, version), instanceName);
        if (persistedInstance == null) {
          String message = "Instance  " + instanceEntity.getViewName() + " can not be found.";

          LOG.error(message);
          throw new IllegalStateException(message);
        }
        instanceEntity.setViewInstanceId(persistedInstance.getViewInstanceId());

        try {
          // bind the view instance to a view
          bindViewInstance(viewEntity, instanceEntity);
        } catch (Exception e) {
          String message = "Caught exception installing view instance.";
          LOG.error(message, e);
          throw new IllegalStateException(message, e);
        }
        // update the registry
        addInstanceDefinition(viewEntity, instanceEntity);
      }
    } else {
      String message = "Attempt to install an instance for an unknown view " +
          instanceEntity.getViewName() + ".";

      LOG.error(message);
      throw new IllegalArgumentException(message);
    }
  }

  /**
   * Update a view instance for the view with the given view name.
   *
   * @param instanceEntity  the view instance entity
   *
   * @throws IllegalStateException if the given instance is not in a valid state
   */
  public void updateViewInstance(ViewInstanceEntity instanceEntity)
      throws IllegalStateException {
    ViewEntity viewEntity = getDefinition(instanceEntity.getViewName());

    if (viewEntity != null) {
      String instanceName = instanceEntity.getName();
      String viewName     = viewEntity.getCommonName();
      String version      = viewEntity.getVersion();

      ViewInstanceEntity entity = getInstanceDefinition(viewName, version, instanceName);

      if (entity != null) {
        if (LOG.isDebugEnabled()) {
          LOG.debug("Updating view instance " + viewName + "/" +
              version + "/" + instanceName);
        }
        entity.setLabel(instanceEntity.getLabel());
        entity.setDescription(instanceEntity.getDescription());
        entity.setVisible(instanceEntity.isVisible());
        entity.setProperties(instanceEntity.getProperties());
        entity.setData(instanceEntity.getData());

        instanceEntity.validate(viewEntity);
        instanceDAO.merge(entity);
      }
    }
  }

  /**
   * Remove the data entry keyed by the given key from the given instance entity.
   *
   * @param instanceEntity  the instance entity
   * @param key             the data key
   */
  public void removeInstanceData(ViewInstanceEntity instanceEntity, String key) {
    ViewInstanceDataEntity dataEntity = instanceEntity.getInstanceData(key);
    if (dataEntity != null) {
      instanceDAO.removeData(dataEntity);
    }
    instanceEntity.removeInstanceData(key);
    instanceDAO.merge(instanceEntity);
  }

  /**
   * Uninstall a view instance for the view with the given view name.
   *
   * @param instanceEntity  the view instance entity
   */
  public void uninstallViewInstance(ViewInstanceEntity instanceEntity) {
    ViewEntity viewEntity = getDefinition(instanceEntity.getViewName());

    if (viewEntity != null) {
      String instanceName = instanceEntity.getName();
      String viewName     = viewEntity.getCommonName();
      String version      = viewEntity.getVersion();

      if (getInstanceDefinition(viewName, version, instanceName) != null) {

        if (LOG.isDebugEnabled()) {
          LOG.debug("Deleting view instance " + viewName + "/" +
              version + "/" +instanceName);
        }
        instanceDAO.remove(instanceEntity);
        viewEntity.removeInstanceDefinition(instanceName);
        removeInstanceDefinition(viewEntity, instanceName);
      }
    }
  }

  /**
   * Get a WebAppContext for the given view instance.
   *
   * @param viewInstanceDefinition  the view instance definition
   *
   * @return a web app context
   *
   * @throws SystemException if an application context can not be obtained for the given view instance
   */
  public WebAppContext getWebAppContext(ViewInstanceEntity viewInstanceDefinition)
      throws SystemException{
    try {
      ViewEntity viewDefinition = viewInstanceDefinition.getViewEntity();

      WebAppContext context = new WebAppContext(viewDefinition.getArchive(), viewInstanceDefinition.getContextPath());
      context.setClassLoader(viewDefinition.getClassLoader());
      context.setAttribute(ViewContext.CONTEXT_ATTRIBUTE, new ViewContextImpl(viewInstanceDefinition, this));
      return context;
    } catch (Exception e) {
      throw new SystemException("Can't get application context for view " +
          viewInstanceDefinition.getViewEntity().getCommonName() + ".", e);
    }
  }

  /**
   * Notify any registered listeners of the given event.
   *
   * @param event  the event
   */
  public void fireEvent(Event event) {

    ViewDefinition subject = event.getViewSubject();

    fireEvent(event, subject.getViewName());
    fireEvent(event, ViewEntity.getViewName(subject.getViewName(), subject.getVersion()));
  }

  /**
   * Register the given listener to listen for events from the view identified by the given name and version.
   *
   * @param listener     the listener
   * @param viewName     the view name
   * @param viewVersion  the view version; null indicates all versions
   */
  public synchronized void registerListener(Listener listener, String viewName, String viewVersion) {

    String name = viewVersion == null ? viewName : ViewEntity.getViewName(viewName, viewVersion);

    List<Listener> listeners = this.listeners.get(name);

    if (listeners == null) {
      listeners = new LinkedList<Listener>();
      this.listeners.put(name, listeners);
    }

    listeners.add(listener);
  }


  // ----- helper methods ----------------------------------------------------

  /**
   * Clear the registry.
   */
  protected void clear() {
    viewDefinitions.clear();
    viewInstanceDefinitions.clear();
    subResourceDefinitionsMap.clear();
    listeners.clear();
  }

  /**
   * Set the helper.
   *
   * @param helper  the helper
   */
  protected void setHelper(ViewRegistryHelper helper) {
    this.helper = helper;
  }

  // get a view entity for the given internal view name
  private ViewEntity getDefinition(String viewName) {
    return viewDefinitions.get(viewName);
  }

  // create a new view definition
  protected ViewEntity createViewDefinition(ViewConfig viewConfig, Configuration ambariConfig,
                                          ClassLoader cl, String archivePath)
      throws ClassNotFoundException, IntrospectionException {

    ViewEntity viewDefinition = new ViewEntity(viewConfig, ambariConfig, cl, archivePath);

    List<ParameterConfig> parameterConfigurations = viewConfig.getParameters();

    Collection<ViewParameterEntity> parameters = new HashSet<ViewParameterEntity>();
    for (ParameterConfig parameterConfiguration : parameterConfigurations) {
      ViewParameterEntity viewParameterEntity =  new ViewParameterEntity();

      viewParameterEntity.setViewName(viewDefinition.getName());
      viewParameterEntity.setName(parameterConfiguration.getName());
      viewParameterEntity.setDescription(parameterConfiguration.getDescription());
      viewParameterEntity.setRequired(parameterConfiguration.isRequired());
      viewParameterEntity.setViewEntity(viewDefinition);
      parameters.add(viewParameterEntity);
    }
    viewDefinition.setParameters(parameters);

    List<ResourceConfig> resourceConfigurations = viewConfig.getResources();

    Resource.Type externalResourceType = viewDefinition.getExternalResourceType();

    ViewExternalSubResourceProvider viewExternalSubResourceProvider =
        new ViewExternalSubResourceProvider(externalResourceType, viewDefinition);
    viewDefinition.addResourceProvider(externalResourceType, viewExternalSubResourceProvider );

    ResourceInstanceFactoryImpl.addResourceDefinition(externalResourceType,
        new ViewExternalSubResourceDefinition(externalResourceType));

    Collection<ViewResourceEntity> resources = new HashSet<ViewResourceEntity>();
    for (ResourceConfig resourceConfiguration : resourceConfigurations) {
      ViewResourceEntity viewResourceEntity = new ViewResourceEntity();

      viewResourceEntity.setViewName(viewDefinition.getName());
      viewResourceEntity.setName(resourceConfiguration.getName());
      viewResourceEntity.setPluralName(resourceConfiguration.getPluralName());
      viewResourceEntity.setIdProperty(resourceConfiguration.getIdProperty());
      viewResourceEntity.setResource(resourceConfiguration.getResource());
      viewResourceEntity.setService(resourceConfiguration.getService());
      viewResourceEntity.setProvider(resourceConfiguration.getProvider());
      viewResourceEntity.setSubResourceNames(resourceConfiguration.getSubResourceNames());
      viewResourceEntity.setViewEntity(viewDefinition);

      ViewSubResourceDefinition resourceDefinition = new ViewSubResourceDefinition(viewDefinition, resourceConfiguration);
      viewDefinition.addResourceDefinition(resourceDefinition);

      Resource.Type type = resourceDefinition.getType();
      viewDefinition.addResourceConfiguration(type, resourceConfiguration);

      if (resourceConfiguration.isExternal()) {
        viewExternalSubResourceProvider.addResourceName(resourceConfiguration.getName());
      } else {
        ResourceInstanceFactoryImpl.addResourceDefinition(type, resourceDefinition);

        Class<?> clazz      = resourceConfiguration.getResourceClass(cl);
        String   idProperty = resourceConfiguration.getIdProperty();

        viewDefinition.addResourceProvider(type, new ViewSubResourceProvider(type, clazz, idProperty, viewDefinition));

        resources.add(viewResourceEntity);
      }
      viewDefinition.setResources(resources);
    }
    View view = null;
    if (viewConfig.getView() != null) {
      view = getView(viewConfig.getViewClass(cl), new ViewContextImpl(viewDefinition, this));
    }
    viewDefinition.setView(view);

    return viewDefinition;
  }

  // create a new view instance definition
  protected ViewInstanceEntity createViewInstanceDefinition(ViewEntity viewDefinition, InstanceConfig instanceConfig)
      throws ClassNotFoundException, IllegalStateException {
    ViewInstanceEntity viewInstanceDefinition =
        new ViewInstanceEntity(viewDefinition, instanceConfig);

    for (PropertyConfig propertyConfig : instanceConfig.getProperties()) {
      viewInstanceDefinition.putProperty(propertyConfig.getKey(), propertyConfig.getValue());
    }
    viewInstanceDefinition.validate(viewDefinition);

    bindViewInstance(viewDefinition, viewInstanceDefinition);
    return viewInstanceDefinition;
  }

  // bind a view instance definition to the given view definition
  protected void bindViewInstance(ViewEntity viewDefinition,
                                   ViewInstanceEntity viewInstanceDefinition)
      throws ClassNotFoundException {
    viewInstanceDefinition.setViewEntity(viewDefinition);

    ViewContext viewInstanceContext = new ViewContextImpl(viewInstanceDefinition, this);

    ViewExternalSubResourceService externalSubResourceService =
        new ViewExternalSubResourceService(viewDefinition.getExternalResourceType(), viewInstanceDefinition);

    viewInstanceDefinition.addService(ResourceConfig.EXTERNAL_RESOURCE_PLURAL_NAME, externalSubResourceService);

    Collection<ViewSubResourceDefinition> resourceDefinitions = viewDefinition.getResourceDefinitions().values();
    for (ViewSubResourceDefinition resourceDefinition : resourceDefinitions) {

      Resource.Type  type           = resourceDefinition.getType();
      ResourceConfig resourceConfig = resourceDefinition.getResourceConfiguration();

      ViewResourceHandler viewResourceService = new ViewSubResourceService(type, viewInstanceDefinition);

      ClassLoader cl = viewDefinition.getClassLoader();

      Object service = getService(resourceConfig.getServiceClass(cl), viewResourceService, viewInstanceContext);

      if (resourceConfig.isExternal()) {
        externalSubResourceService.addResourceService(resourceConfig.getName(), service);
      } else {
        viewInstanceDefinition.addService(viewDefinition.getResourceDefinition(type).getPluralName(),service);
        viewInstanceDefinition.addResourceProvider(type,
            getProvider(resourceConfig.getProviderClass(cl), viewInstanceContext));
      }
    }

    setPersistenceEntities(viewInstanceDefinition);

    viewDefinition.addInstanceDefinition(viewInstanceDefinition);
  }

  // Set the entities defined in the view persistence element for the given view instance
  private static void setPersistenceEntities(ViewInstanceEntity viewInstanceDefinition) {
    ViewEntity        viewDefinition    = viewInstanceDefinition.getViewEntity();
    ViewConfig        viewConfig        = viewDefinition.getConfiguration();

    Collection<ViewEntityEntity> entities = new HashSet<ViewEntityEntity>();

    if (viewConfig != null) {
      PersistenceConfig persistenceConfig = viewConfig.getPersistence();

      if (persistenceConfig != null) {
        for (EntityConfig entityConfiguration : persistenceConfig.getEntities()) {
          ViewEntityEntity viewEntityEntity = new ViewEntityEntity();

          viewEntityEntity.setViewName(viewDefinition.getName());
          viewEntityEntity.setViewInstanceName(viewInstanceDefinition.getName());
          viewEntityEntity.setClassName(entityConfiguration.getClassName());
          viewEntityEntity.setIdProperty(entityConfiguration.getIdProperty());
          viewEntityEntity.setViewInstance(viewInstanceDefinition);

          entities.add(viewEntityEntity);
        }
      }
    }
    viewInstanceDefinition.setEntities(entities);
  }

  // get the given service class from the given class loader; inject a handler and context
  private static <T> T getService(Class<T> clazz,
                                  final ViewResourceHandler viewResourceHandler,
                                  final ViewContext viewInstanceContext) {
    Injector viewInstanceInjector = Guice.createInjector(new AbstractModule() {
      @Override
      protected void configure() {
        bind(ViewResourceHandler.class)
            .toInstance(viewResourceHandler);
        bind(ViewContext.class)
            .toInstance(viewInstanceContext);
      }
    });
    return viewInstanceInjector.getInstance(clazz);
  }

  // get the given resource provider class from the given class loader; inject a context
  private static org.apache.ambari.view.ResourceProvider getProvider(
      Class<? extends org.apache.ambari.view.ResourceProvider> clazz,
      final ViewContext viewInstanceContext) {
    Injector viewInstanceInjector = Guice.createInjector(new AbstractModule() {
      @Override
      protected void configure() {
        bind(ViewContext.class)
            .toInstance(viewInstanceContext);
      }
    });
    return viewInstanceInjector.getInstance(clazz);
  }

  // get the given view class from the given class loader; inject a context
  private static View getView(Class<? extends View> clazz,
                              final ViewContext viewContext) {
    Injector viewInstanceInjector = Guice.createInjector(new AbstractModule() {
      @Override
      protected void configure() {
        bind(ViewContext.class)
            .toInstance(viewContext);
      }
    });
    return viewInstanceInjector.getInstance(clazz);
  }

  // remove undeployed views from the ambari db
  private void removeUndeployedViews() {
    for (ViewEntity viewEntity : viewDAO.findAll()) {
      String name = viewEntity.getName();
      if (!ViewRegistry.getInstance().viewDefinitions.containsKey(name)) {
        try {
          viewDAO.remove(viewEntity);
        } catch (Exception e) {
          LOG.error("Caught exception undeploying view " + viewEntity.getName(), e);
        }
      }
    }
  }

  // sync the given view with the db
  private void syncView(ViewEntity view,
                        Set<ViewInstanceEntity> instanceDefinitions)
      throws Exception {

    String viewName = view.getName();

    ViewEntity persistedView = viewDAO.findByName(viewName);

    // if the view is not yet persisted ...
    if (persistedView == null) {
      if (LOG.isDebugEnabled()) {
        LOG.debug("Creating View " + viewName + ".");
      }
      // ... merge it
      viewDAO.merge(view);

      persistedView = viewDAO.findByName(viewName);
      if (persistedView == null) {
        String message = "View  " + persistedView.getViewName() + " can not be found.";

        LOG.error(message);
        throw new IllegalStateException(message);
      }
    }

    Map<String, ViewInstanceEntity> instanceEntityMap = new HashMap<String, ViewInstanceEntity>();
    for( ViewInstanceEntity instance : view.getInstances()) {
      instanceEntityMap.put(instance.getName(), instance);
    }

    // make sure that each instance of the view in the db is reflected in the given view
    for (ViewInstanceEntity persistedInstance : persistedView.getInstances()){
      String instanceName = persistedInstance.getName();

      ViewInstanceEntity instance =
          view.getInstanceDefinition(instanceName);

      instanceEntityMap.remove(instanceName);

      // if the persisted instance is not in the registry ...
      if (instance == null) {
        // ... create and add it
        instance = new ViewInstanceEntity(view, instanceName);
        bindViewInstance(view, instance);
        instanceDefinitions.add(instance);
      }
      instance.setViewInstanceId(persistedInstance.getViewInstanceId());

      // apply the persisted overrides to the in-memory instance
      instance.setLabel(persistedInstance.getLabel());
      instance.setDescription(persistedInstance.getDescription());
      instance.setVisible(persistedInstance.isVisible());
      instance.setData(persistedInstance.getData());
      instance.setProperties(persistedInstance.getProperties());
      instance.setEntities(persistedInstance.getEntities());
    }

    // these instances appear in the archive but have been deleted
    // from the db... remove them from the registry
    for (ViewInstanceEntity instance : instanceEntityMap.values()) {
      view.removeInstanceDefinition(instance.getName());
      instanceDefinitions.remove(instance);
    }
  }

  // ensure that the extracted view archive directory exists
  private boolean ensureExtractedArchiveDirectory(String extractedArchivesPath) {
    File extractedArchiveDir = helper.getFile(extractedArchivesPath);

    if (!extractedArchiveDir.exists()) {
      if (!extractedArchiveDir.mkdir()) {
        LOG.error("Could not create extracted view archive directory " +
            extractedArchivesPath + ".");
        return false;
      }
    }
    return true;
  }

  // extract the given view archive to the given archive directory
  private ClassLoader extractViewArchive(File viewArchive, File archiveDir)
      throws IOException {

    // Skip if the archive has already been extracted
    if (!archiveDir.exists()) {

      String archivePath = archiveDir.getAbsolutePath();

      LOG.info("Creating archive folder " + archivePath + ".");
     
      if (archiveDir.mkdir()) {
        JarFile     viewJarFile = helper.getJarFile(viewArchive);
        Enumeration enumeration = viewJarFile.entries();

        LOG.info("Extracting files from " + viewArchive.getName() + ":");

        while (enumeration.hasMoreElements()) {
          JarEntry jarEntry  = (JarEntry) enumeration.nextElement();
          String   entryPath = archivePath + File.separator + jarEntry.getName();

          LOG.info("    " + entryPath);

          File entryFile = helper.getFile(entryPath);

          if (jarEntry.isDirectory()) {
            if (!entryFile.mkdir()) {
              LOG.error("Could not create archive entry directory " + entryPath + ".");
            }
          } else {
            InputStream is = viewJarFile.getInputStream(jarEntry);
            try {
              FileOutputStream fos = helper.getFileOutputStream(entryFile);
              try {
                while (is.available() > 0) {
                  fos.write(is.read());
                }
              } finally {
                fos.close();
              }
            } finally {
              is.close();
            }
          }
        }
      } else {
        LOG.error("Could not create archive directory " + archivePath + ".");
      }
    }
    return getArchiveClassLoader(archiveDir);
  }

  // get a class loader for the given archive directory
  private ClassLoader getArchiveClassLoader(File archiveDir)
      throws MalformedURLException {

    String    archivePath = archiveDir.getAbsolutePath();
    List<URL> urlList     = new LinkedList<URL>();

    // include the classes directory
    String classesPath = archivePath + File.separator + ARCHIVE_CLASSES_DIR;
    File   classesDir  = helper.getFile(classesPath);
    if (classesDir.exists()) {
      urlList.add(classesDir.toURI().toURL());
    }

    // include any libraries in the lib directory
    String libPath = archivePath + File.separator + ARCHIVE_LIB_DIR;
    File   libDir  = helper.getFile(libPath);
    if (libDir.exists()) {
      File[] files = libDir.listFiles();
      if (files != null) {
        for (final File fileEntry : files) {
          if (!fileEntry.isDirectory()) {
            urlList.add(fileEntry.toURI().toURL());
          }
        }
      }
    }

    // include the archive directory
    urlList.add(archiveDir.toURI().toURL());

    return URLClassLoader.newInstance(urlList.toArray(new URL[urlList.size()]));
  }

  // notify the view identified by the given view name of the given event
  private void fireEvent(Event event, String viewName) {
    List<Listener> listeners = this.listeners.get(viewName);

    if (listeners != null) {
      for (Listener listener : listeners) {
        listener.notify(event);
      }
    }
  }

  /**
   * Static initialization of DAO.
   *
   * @param viewDAO      view data access object
   * @param instanceDAO  view instance data access object
   */
  public static void init(ViewDAO viewDAO, ViewInstanceDAO instanceDAO) {
    setViewDAO(viewDAO);
    setInstanceDAO(instanceDAO);
  }

  /**
   * Set the view DAO.
   *
   * @param viewDAO  the view DAO
   */
  protected static void setViewDAO(ViewDAO viewDAO) {
    ViewRegistry.viewDAO = viewDAO;
  }

  /**
   * Set the instance DAO.
   *
   * @param instanceDAO  the instance DAO
   */
  protected static void setInstanceDAO(ViewInstanceDAO instanceDAO) {
    ViewRegistry.instanceDAO = instanceDAO;
  }


  // ----- inner class : ViewRegistryHelper ----------------------------------

  /**
   * Registry helper class.
   */
  protected static class ViewRegistryHelper {

    /**
     * Get the view configuration from the given archive file.
     *
     * @param archiveFile  the archive file
     *
     * @return the associated view configuration
     */
    public ViewConfig getViewConfigFromArchive(File archiveFile)
        throws MalformedURLException, JAXBException {
      ClassLoader cl = URLClassLoader.newInstance(new URL[]{archiveFile.toURI().toURL()});

      InputStream  configStream     = cl.getResourceAsStream(VIEW_XML);
      JAXBContext  jaxbContext      = JAXBContext.newInstance(ViewConfig.class);
      Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();

      return (ViewConfig) jaxbUnmarshaller.unmarshal(configStream);
    }

    /**
     * Get a new file instance for the given path.
     *
     * @param path  the path
     *
     * @return a new file instance
     */
    public File getFile(String path) {
      return new File(path);
    }

    /**
     * Get a new file output stream for the given file.
     *
     * @param file  the file
     *
     * @return a new file output stream
     */
    public FileOutputStream getFileOutputStream(File file) throws FileNotFoundException {
      return new FileOutputStream(file);
    }

    /**
     * Get a new jar file instance from the given file.
     *
     * @param file  the file
     *
     * @return a new jar file instance
     */
    public JarFile getJarFile(File file) throws IOException {
      return new JarFile(file);
    }
  }
}
TOP

Related Classes of org.apache.ambari.server.view.ViewRegistry

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.