Package org.cruxframework.crux.core.rebind.screen

Source Code of org.cruxframework.crux.core.rebind.screen.ScreenFactory

/*
* Copyright 2011 cruxframework.org.
*
* Licensed 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.cruxframework.crux.core.rebind.screen;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.cruxframework.crux.core.rebind.module.Module;
import org.cruxframework.crux.core.rebind.module.Modules;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;


/**
* Creates a representation for Crux screens
* @author Thiago Bustamante
*
*/
public class ScreenFactory
{
  private static ScreenFactory instance = new ScreenFactory();
 
  private static final Lock screenLock = new ReentrantLock();
  private static final long UNCHANGED_RESOURCE = -1;
  private static final long REPROCESS_RESOURCE = -2

  private Map<String, Screen> screenCache = new HashMap<String, Screen>();
  private Map<String, Long> screenLastModified = new HashMap<String, Long>();   

  /**
   * Singleton Constructor
   */
  private ScreenFactory()
  {
  }
 
  /**
   * Singleton method
   * @return
   */
  public static ScreenFactory getInstance()
  {
    return instance;
  }
 
  /**
   * Clear the screen cache
   */
  public void clearScreenCache()
  {
    screenCache.clear();
    ViewFactory.getInstance().clearViewCache();
  }
 
  /**
   * Factory method for screens.
   * @param id
   * @param device device property for this permutation being compiled
   * @return
   * @throws ScreenConfigException
   */
  public Screen getScreen(String id, String device) throws ScreenConfigException
  {
    try
    {
      long lastModified = getScreenLastModified(id);
      String cacheId = device==null?id:id+"_"+device;
     
      Screen screen = getFromCache(id, cacheId, lastModified);
      if (screen != null)
      {
        return screen;
      }

     
      screenLock.lock();
      try
      {
        if (getFromCache(id, cacheId, lastModified) == null)
        {
          Document screenView;
          String relativeScreenId = Modules.getInstance().removeModuleIfPresent(id);
            if (!relativeScreenId.equals(id))
            {
              String module = id.substring(0, id.indexOf("/"));
              screenView = ScreenResourceResolverInitializer.getScreenResourceResolver().getRootView(relativeScreenId, module, device);
            }
            else
            {
              screenView = ScreenResourceResolverInitializer.getScreenResourceResolver().getRootView(id, device);
            }
           
          if (screenView == null)
          {
            throw new ScreenConfigException("Screen ["+id+"] not found!");
          }
          screen = parseScreen(id, device, screenView);
          if(screen != null)
          {
            screenCache.put(cacheId, screen);
            saveScreenLastModified(cacheId, lastModified);
          }
        }
      }
      finally
      {
        screenLock.unlock();
      }
      return getFromCache(id, cacheId, lastModified);
     
    }
    catch (Throwable e)
    {
      throw new ScreenConfigException("Error retrieving screen ["+id+"].", e);
    }
  }

  /**
   * @param id
   * @param module
   * @return
   * @throws ScreenConfigException
   */
  public String getRelativeScreenId(String id, String module) throws ScreenConfigException
  {
    Module mod = Modules.getInstance().getModule(module);
    if (mod == null)
    {
      throw new ScreenConfigException("No module declared on screen ["+id+"].");
    }
    return Modules.getInstance().getRelativeScreenId(mod, id);
  }
 
  /**
   * @param nodeList
   * @return
   * @throws ScreenConfigException
   */
  public String getScreenModule(Document source) throws ScreenConfigException
  {
    String result = null;
   
    NodeList nodeList = source.getElementsByTagName("script");
    int length = nodeList.getLength();
    for (int i = 0; i < length; i++)
    {
      Element item = (Element) nodeList.item(i);
     
      String src = item.getAttribute("src");
     
      if (src != null && src.endsWith(".nocache.js"))
      {
        if (result != null)
        {
          throw new ScreenConfigException("Multiple modules in the same html page is not allowed in CRUX.");
        }
       
        int lastSlash = src.lastIndexOf("/");
       
        if(lastSlash >= 0)
        {
          int firstDotAfterSlash = src.indexOf(".", lastSlash);
          result = src.substring(lastSlash + 1, firstDotAfterSlash);
        }
        else
        {
          int firstDot = src.indexOf(".");
          result = src.substring(0, firstDot);
        }
      }
    }
    return result;
  }
 
  /**
   *
   * @param id
   * @param cacheId
   * @param lastModified
   * @return
   */
  private Screen getFromCache(String id,String cacheId, long lastModified)
  {
    Screen screen = screenCache.get(cacheId);
    if (screen != null)
    {
      if (mustReprocessScreen(cacheId, lastModified))
      {
        screenCache.remove(cacheId);
        screen = null;
      }
    }
    return screen;
  }

  /**
   * @param id
   * @param lastModified
   * @return
   */
  private boolean mustReprocessScreen(String id, long lastModified)
  {
    if (lastModified == REPROCESS_RESOURCE)
    {
      return true;
    }
    if (lastModified == UNCHANGED_RESOURCE)
    {
      return false;
    }
   
    return (!screenLastModified.containsKey(id) || !screenLastModified.get(id).equals(lastModified));
  }

  /**
   * @param id
   * @param lastModified
   */
  private void saveScreenLastModified(String id, long lastModified)
  {
      if (id.toLowerCase().startsWith("file:"))
      {
        screenLastModified.put(id, lastModified);
      }
      else
      {
        screenLastModified.put(id, UNCHANGED_RESOURCE);
      }
  }
 
  /**
   * @param id
   * @return
   */
  private long getScreenLastModified(String id)
    {
      if (id.toLowerCase().startsWith("file:"))
      {
        try
            {
              File screenFile = new File(new URL(id).toURI());
              return screenFile.lastModified();
            }
            catch (Exception e)
            {
              return REPROCESS_RESOURCE;
            }
      }
     
      return UNCHANGED_RESOURCE;
    }

  /**
   * Parse the HTML page and build the Crux Screen.
   * @param id
   * @param device
   * @param screenView
   * @return
   * @throws IOException
   * @throws ScreenConfigException
   */
  private Screen parseScreen(String id, String device, Document screenView) throws IOException, ScreenConfigException
  {
    Screen screen = null;
    String screenModule = getScreenModule(screenView);

    if(screenModule != null)
    {
      String relativeScreenId = getRelativeScreenId(id, screenModule);
      View rootView = ViewFactory.getInstance().getView(screenModule+"/"+relativeScreenId, device, screenView, true);
     
      screen = new Screen(id, relativeScreenId, screenModule, rootView);
    }
    else
    {
      throw new ScreenConfigException("No module declared on screen ["+id+"].");
    }
   
    return screen;
  }
}
TOP

Related Classes of org.cruxframework.crux.core.rebind.screen.ScreenFactory

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.