Package org.exoplatform.web.application.javascript

Source Code of org.exoplatform.web.application.javascript.JavascriptConfigService

/**
* Copyright (C) 2009 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.exoplatform.web.application.javascript;

import javax.servlet.ServletContext;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.exoplatform.commons.utils.CompositeReader;
import org.exoplatform.commons.utils.PropertyManager;
import org.exoplatform.container.ExoContainerContext;
import org.exoplatform.portal.resource.AbstractResourceService;
import org.exoplatform.portal.resource.compressor.ResourceCompressor;
import org.exoplatform.web.ControllerContext;
import org.exoplatform.web.controller.router.URIWriter;
import org.gatein.common.logging.Logger;
import org.gatein.common.logging.LoggerFactory;
import org.gatein.portal.controller.resource.ResourceId;
import org.gatein.portal.controller.resource.ResourceScope;
import org.gatein.portal.controller.resource.script.FetchMode;
import org.gatein.portal.controller.resource.script.Module;
import org.gatein.portal.controller.resource.script.ScriptGraph;
import org.gatein.portal.controller.resource.script.ScriptResource;
import org.gatein.wci.WebApp;
import org.gatein.wci.WebAppListener;
import org.gatein.wci.impl.DefaultServletContainerFactory;
import org.json.JSONArray;
import org.json.JSONObject;
import org.picocontainer.Startable;

public class JavascriptConfigService extends AbstractResourceService implements Startable
{

   /** Our logger. */
   private final Logger log = LoggerFactory.getLogger(JavascriptConfigService.class);

   /** The scripts. */
   final ScriptGraph scripts;

   /** . */
   private final WebAppListener deployer;

   /** . */
   public static final Comparator<Module> MODULE_COMPARATOR = new Comparator<Module>()
   {
      public int compare(Module o1, Module o2)
      {
         return o1.getPriority() - o2.getPriority();
      }
   };

   public JavascriptConfigService(ExoContainerContext context, ResourceCompressor compressor)
   {
      super(compressor);

      //
      this.scripts = new ScriptGraph();
      this.deployer = new JavascriptConfigDeployer(context.getPortalContainerName(), this);
   }

   public Collection<String> getAvailableScripts()
   {
      ArrayList<String> list = new ArrayList<String>();
      for (ScriptResource shared : scripts.getResources(ResourceScope.SHARED))
      {
         list.addAll(shared.getModulesNames());
      }
      return list;
   }

   public Collection<String> getAvailableScriptsPaths()
   {
      ArrayList<Module> sharedModules = new ArrayList<Module>();
      for (ScriptResource shared : scripts.getResources(ResourceScope.SHARED))
      {
         sharedModules.addAll(shared.getModules());
      }
      Collections.sort(sharedModules, MODULE_COMPARATOR);
      List<String> paths = new ArrayList<String>();
      for (Module module : sharedModules)
      {
         paths.add(module.getURI());
      }
      return paths;
   }

   public Reader getScript(ResourceId id, String name, Locale locale)
   {
      ScriptResource script = getResource(id);
      if (script != null && !"merged".equals(name))
      {
         return getJavascript(script, name, locale);
      }
      else
      {
         return getScript(id, locale);
      }
   }
  
   public Reader getScript(ResourceId resourceId, Locale locale)
   {
      ScriptResource resource = getResource(resourceId);
     
      if (resource != null)
      {
         List<Module> modules = new ArrayList<Module>(resource.getModules());
         Collections.sort(modules, MODULE_COMPARATOR);
         ArrayList<Reader> readers = new ArrayList<Reader>(modules.size() * 2);
        
         //
         StringBuilder buffer = new StringBuilder();
         boolean isModule = FetchMode.ON_LOAD.equals(resource.getFetchMode());
         if (isModule)
         {
            buffer.append("define('").append(resourceId).append("', ");
            buffer.append(new JSONArray(resource.getDependencies()));           
            buffer.append(", function(");
            for (ResourceId resId : resource.getDependencies())
            {              
               String alias = resource.getDependencyAlias(resId);
               ScriptResource dep = getResource(resId);
               if (dep != null)
               {
                  buffer.append(alias == null ? dep.getAlias() : alias).append(",");                 
               }
            }
            if (buffer.charAt(buffer.length() - 1) == ',')
            {
               buffer.deleteCharAt(buffer.length() - 1);
            }
           
            //                       
            buffer.append(") { var _module = {};(function() {");
         }
        
         //
         for (Module js : modules)
         {
            Reader jScript = getJavascript(resource, js.getName(), locale);
            if (jScript != null)
            {                                                    
               buffer.append("// Begin ").append(js.getName()).append("\n");                         

               //
               readers.add(new StringReader(buffer.toString()));                 
               buffer.setLength(0);                 
               readers.add(jScript);

               //
               buffer.append("// End ").append(js.getName()).append("\n");
            }                                            
         }        
           
         if (isModule)
         {
            buffer.append("})();");
            buffer.append("return _module;});");    
         }
         else
         {
            buffer.append("if (typeof define === 'function' && define.amd) {");
            buffer.append("define('").append(resourceId).append("');}");           
         }
         readers.add(new StringReader(buffer.toString()));
        
         return new CompositeReader(readers);
      }
      else
      {
         return null;        
      }
   }
  
   public Map<String, FetchMode> resolveURLs(
      ControllerContext controllerContext,
      Map<ResourceId, FetchMode> ids,
      boolean merge,
      boolean minified,
      Locale locale) throws IOException
   {
      Map<String, FetchMode> urls = new LinkedHashMap<String, FetchMode>();
      StringBuilder buffer = new StringBuilder();
      URIWriter writer = new URIWriter(buffer);

      //
      if (ids.size() > 0)
      {
         ScriptResource resource = getResource(ids.keySet().iterator().next());
               
         //
         if (resource != null)
         {
            FetchMode mode = resource.getFetchMode();
            List<Module> modules = resource.getModules();
            if (modules.size() > 0 && modules.get(0) instanceof Module.Remote)
            {
               urls.put(((Module.Remote)modules.get(0)).getURI(), mode);
            }
            else
            {
               controllerContext.renderURL(resource.getParameters(minified, locale), writer);
               urls.put(buffer.toString(), mode);
               buffer.setLength(0);
               writer.reset(buffer);
            }           
         }
      }

      //
      return urls;
   }

   public Map<ScriptResource, FetchMode> resolveIds(Map<ResourceId, FetchMode> ids)
   {
      return scripts.resolve(ids);
   }
  
   public JSONObject getJSConfig(ControllerContext controllerContext, Locale locale) throws Exception
   {
      JSONObject paths = new JSONObject();
      JSONObject shim = new JSONObject();     
           
      for (ScriptResource resource : getAllResources())
      {
         String name = resource.getId().toString();
         if (!resource.isEmpty() || ResourceScope.SHARED.equals(resource.getId().getScope()))
         {
            HashMap<ResourceId, FetchMode> ids = new HashMap<ResourceId, FetchMode>();
            ids.put(resource.getId(), null);                    
            Map<String, FetchMode> urlMap = resolveURLs(controllerContext, ids, !PropertyManager.isDevelopping(),
               !PropertyManager.isDevelopping(), locale);        
           
            String url = urlMap.keySet().iterator().next();           
            paths.put(name, url.substring(0, url.length() - ".js".length()));           

            //
            List<Module> modules = resource.getModules();        
            if (FetchMode.IMMEDIATE.equals(resource.getFetchMode()) ||
                     (modules.size() > 0 && modules.get(0) instanceof Module.Remote))
            {
               JSONArray deps = new JSONArray(resource.getDependencies());              
               if (deps.length() > 0)
               {
                  shim.put(name, new JSONObject().put("deps", deps));              
               }
            }
         }        
      }
                
      JSONObject config = new JSONObject();     
      config.put("paths", paths);
      config.put("shim", shim);
      return config;
   }
  
   private List<ScriptResource> getAllResources()
   {
      List<ScriptResource> resources = new LinkedList<ScriptResource>();
      for (ResourceScope scope : ResourceScope.values())
      {
         resources.addAll(scripts.getResources(scope));
      }
      return resources;
   }
  
   public ScriptResource getResource(ResourceId resource)
   {
      return scripts.getResource(resource);
   }

   //TODO: This method should be removed once there is no call to importJavascript from Groovy template
   public ScriptResource getResourceIncludingModule(String moduleName)
   {
      //We accept repeated graph traversing for the moment
      for(ScriptResource sharedRes : scripts.getResources(ResourceScope.SHARED))
      {
         if(sharedRes.getModule(moduleName) != null)
         {
            return sharedRes;
         }
      }

      for(ScriptResource portletRes : scripts.getResources(ResourceScope.PORTLET))
      {
         if(portletRes.getModule(moduleName) != null)
         {
            return portletRes;
         }
      }

      for(ScriptResource portalRes : scripts.getResources(ResourceScope.PORTAL))
      {
         if(portalRes.getModule(moduleName) != null)
         {
            return portalRes;
         }
      }

      return null;
   }

   public boolean isModuleLoaded(CharSequence module)
   {
      return getAvailableScripts().contains(module.toString());
   }
  
   public boolean isJavascriptLoaded(String path)
   {
      for (ScriptResource shared : scripts.getResources(ResourceScope.SHARED))
      {
         for (Module module : shared.getModules())
         {
            if (module.getURI().equals(path))
            {
               return true;
            }
         }
      }     
      return false;
   }

   /**
    * Start service.
    * Registry org.exoplatform.web.application.javascript.JavascriptDeployer,
    * org.exoplatform.web.application.javascript.JavascriptRemoval  into ServletContainer
    * @see org.picocontainer.Startable#start()
    */
   public void start()
   {
      log.debug("Registering JavascriptConfigService for servlet container events");
      DefaultServletContainerFactory.getInstance().getServletContainer().addWebAppListener(deployer);
   }

   /**
    * Stop service.
    * Remove org.exoplatform.web.application.javascript.JavascriptDeployer,
    * org.exoplatform.web.application.javascript.JavascriptRemoval  from ServletContainer
    * @see org.picocontainer.Startable#stop()
    */
   public void stop()
   {
      log.debug("Unregistering JavascriptConfigService for servlet container events");
      DefaultServletContainerFactory.getInstance().getServletContainer().removeWebAppListener(deployer);
   }
  
   private Reader getJavascript(ScriptResource resource, String moduleName, Locale locale)
   {
      Module module = resource.getModule(moduleName);
      if (module instanceof Module.Local)
      {
         Module.Local localModule = (Module.Local)module;
         final WebApp webApp = contexts.get(localModule.getContextPath());
         if (webApp != null)
         {
            ServletContext sc = webApp.getServletContext();
            return localModule.read(locale, sc, webApp.getClassLoader());
         }
      }
      return null;
   }
}
TOP

Related Classes of org.exoplatform.web.application.javascript.JavascriptConfigService

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.