您的位置:首页 > 产品设计 > UI/UE

PHP中全局变量$_REQUEST、 $_GET、 $_POST、 $_COOKIE 的关系和区别

2011-03-02 22:24 926 查看
  本文介绍如何以外部war应用的方式向liferay portal集成portlet, 还是以sample-jsp-portlet为例来说明。

一,portlet如何被liferay portal调用?

在web-xml定义中,可以看到这样的一个servlet定义:  

 〈servlet〉

  〈servlet-name〉sample_jsp_portlet〈/servlet-name〉

  〈servlet-class〉com.liferay.portal.kernel.servlet.PortletServlet〈/servlet-class〉

  〈init-param〉

   〈param-name〉portlet-class〈/param-name〉

   〈param-value〉com.sample.jsp.portlet.JSPPortlet〈/param-value〉

  〈/init-param〉

  〈load-on-startup〉0〈/load-on-startup〉

 〈/servlet〉

 〈servlet-mapping〉

  〈servlet-name〉sample_jsp_portlet〈/servlet-name〉

  〈url-pattern〉/sample_jsp_portlet/*〈/url-pattern〉

 〈/servlet-mapping〉

在[Liferay中action的处理流程]一文中,分析了当portlet是一个war时,liferay portal将转发请求到war应用,代码如下:

  CachePortlet

    private void _invoke(

   PortletRequest req, PortletResponse res, boolean action)

 throws IOException, PortletException {

 if (_portletConfig.isWARFile()) {

  String path =

   StringPool.SLASH + _portletConfig.getPortletName() + "/invoke";

  RequestDispatcher rd =

   _portletCtx.getServletContext().getRequestDispatcher(path);

  // 一些初始化代码....

  httpReq.setAttribute(WebKeys.JAVAX_PORTLET_PORTLET, _portlet);

  rd.include(httpReq, httpRes);

 }

 else {

  // 略...

 }

  }

  在本文中portletName为sample_jsp_portlet,则path为/sample_jsp_portlet/invoke,这个url对应的servlet就是PortletServlet了,

  这样liferay portlet就将请求转发到了sample-jsp-portlet应用。

  这里要注意的是servlet-name与url-pattern的名称一定要保持一致!

// PortletServlet

 public class PortletServlet extends HttpServlet {

 public static final String JAVAX_PORTLET_PORTLET = "javax.portlet.portlet";

 public static final String JAVAX_PORTLET_REQUEST = "javax.portlet.request";

 public static final String JAVAX_PORTLET_RESPONSE = "javax.portlet.response";

 public static final String PORTLET_CLASS_LOADER = "PORTLET_CLASS_LOADER";

 public void service(HttpServletRequest req, HttpServletResponse res)

  throws IOException, ServletException {

  PortletRequest portletReq =

   (PortletRequest)req.getAttribute(JAVAX_PORTLET_REQUEST);

  PortletResponse portletRes =

   (PortletResponse)req.getAttribute(JAVAX_PORTLET_RESPONSE);

  Portlet portlet = (Portlet)req.getAttribute(JAVAX_PORTLET_PORTLET);

  LiferayPortletSession portletSes =

   (LiferayPortletSession)portletReq.getPortletSession();

  portletSes.setHttpSession(req.getSession());

  if (portletReq instanceof ActionRequest) {

   ActionRequest actionReq = (ActionRequest)portletReq;

   ActionResponse actionRes = (ActionResponse)portletRes;

   portlet.processAction(actionReq, actionRes);

  }

  else {

   RenderRequest renderReq = (RenderRequest)portletReq;

   RenderResponse renderRes = (RenderResponse)portletRes;

   portlet.render(renderReq, renderRes);

  }

 }

 }

PortletServlet很简单,它根据PortletRequest的类型来决定是让portlet执行processAction还是render,

portlet由servlet定义的init-param参数指定,它必须继承自javax.portlet.GenericPortlet类, 这是jsr168规范所指定的,

本文中为com.sample.jsp.portlet.JSPPortlet。

// JSPPortlet.

 public class JSPPortlet extends GenericPortlet {

 public void init() throws PortletException {

  editJSP = getInitParameter("edit-jsp");

  helpJSP = getInitParameter("help-jsp");

  viewJSP = getInitParameter("view-jsp");

 }

 public void doDispatch(RenderRequest req, RenderResponse res)

  throws IOException, PortletException {

  // 略...

 }

 public void doEdit(RenderRequest req, RenderResponse res)

  throws IOException, PortletException {

  // 略...

 }

 public void doHelp(RenderRequest req, RenderResponse res)

  throws IOException, PortletException {

  include(helpJSP, req, res);

 }

 public void doView(RenderRequest req, RenderResponse res)

  throws IOException, PortletException {

  include(viewJSP, req, res);

 }

 public void processAction(ActionRequest req, ActionResponse res)

  throws IOException, PortletException {

 }

 protected void include(String path, RenderRequest req, RenderResponse res)

  throws IOException, PortletException {

  PortletRequestDispatcher prd =

   getPortletContext().getRequestDispatcher(path);

  if (prd == null) {

   _log.error(path + " is not a valid include");

  }

  else {

   prd.include(req, res);

  }

 }

 }

这里一个很简单的portlet实现,它直接包含jsp文件。

二,portlet中的预定义对象.

portlet 页面上能使用的对象.

首先在portlet页面上加入如下tag定义,

<portlet:defineobjects></portlet:defineobjects>

 DefineObjectsTag.doStartTag() {

 ClassLoader contextClassLoader =

  Thread.currentThread().getContextClassLoader();

 try {

  // 切换ClassLoader,对于采用War方式的portlet,这是必须的?

  Thread.currentThread().setContextClassLoader(

   PortalClassLoaderUtil.getClassLoader());

  MethodWrapper methodWrapper = new MethodWrapper(

   _TAG_CLASS, _TAG_DO_START_METHOD, new Object[] {pageContext});

  MethodInvoker.invoke(methodWrapper);

 }

 catch (Exception e) {

  throw new JspException(e);

 }

 finally {

  Thread.currentThread().setContextClassLoader(contextClassLoader);

 }

 return SKIP_BODY; 

 }

 private static final String _TAG_CLASS =

  "com.liferay.portlet.DefineObjectsTagUtil";

 private static final String _TAG_DO_START_METHOD = "doStartTag";

 DefineObjectsTag.doStartTag(PageContext pageContext) {

 ServletRequest req = pageContext.getRequest();

 PortletConfigImpl portletConfig =

  (PortletConfigImpl)req.getAttribute(WebKeys.JAVAX_PORTLET_CONFIG);

 if (portletConfig != null) {

  pageContext.setAttribute("portletConfig", portletConfig);

  pageContext.setAttribute(

   "portletName", portletConfig.getPortletName());

 }

 RenderRequest renderRequest =

  (RenderRequest)req.getAttribute(WebKeys.JAVAX_PORTLET_REQUEST);

 if (renderRequest != null) {

  pageContext.setAttribute("renderRequest", renderRequest);

  pageContext.setAttribute(

   "portletPreferences", renderRequest.getPreferences());

  pageContext.setAttribute(

   "portletSession", renderRequest.getPortletSession());

 }

 RenderResponse renderResponse =

  (RenderResponse)req.getAttribute(WebKeys.JAVAX_PORTLET_RESPONSE);

 if (renderResponse != null) {

  pageContext.setAttribute("renderResponse", renderResponse);

 }

 if (portletConfig.isWARFile() && ServerDetector.isWebLogic()) {

  PortletSessionImpl portletSession =

   (PortletSessionImpl)renderRequest.getPortletSession();

  PortletSessionPool.put(

   portletSession.getPortalSessionId(), pageContext.getSession());

 }

 }

从上面的代码可以看出,在portlet的页面上可以直接使用的对象有:

portletConfig  // portlet配置.

portletName   // portlet名称.

renderRequest  // portlet request.

portletPreferences // portlet 首选项.

portletSession // portlet 会话.

renderResponse // portlet response.

三,portlets如何部署到liferay portal中?

在portlets应用的web.xml中加入如下listener定义:

 
<listener></listener>

    
<listener-class></listener-class>
com.liferay.portal.kernel.servlet.PortletContextListener

 

加入了此listener后,当portlets应用启动时,将会向liferay portal注册此应用中的所有定义的portlet;

当portlets应用停止时,会向liferay portal取消所有定义的portlet,  portlet定义当然是由portlet.xml文件给出。

 PortletContextListener实现了ServletContextListener接口.

   public class PortletContextListener implements ServletContextListener {

 public void contextInitialized(ServletContextEvent sce) {

  HotDeployUtil.fireDeployEvent(

   new HotDeployEvent(

    sce.getServletContext(),

    Thread.currentThread().getContextClassLoader()));

 }

 public void contextDestroyed(ServletContextEvent sce) {

  HotDeployUtil.fireUndeployEvent(

   new HotDeployEvent(

    sce.getServletContext(),

    Thread.currentThread().getContextClassLoader()));

 }

  }

  上面的两个方法直接调用HotDeployUtil的fireDeployEvent和fireUndeployEvent方法,HotDeployUtil是Liferay portal的热部署工具类,

  下面来着重看看fireDeployEvent是如何执行portlet注册的,

  public class HotDeployUtil {

 // 构造一个实例,singlton模式.

 private static HotDeployUtil _instance = new HotDeployUtil();

 // 触发部署事件,通知HotDeployListener进行部署。

 private synchronized void _fireDeployEvent(HotDeployEvent event) {

 

             // 当_events不为空时,说明liferay portal还没启动,此时只是简单的保存event.

      if (_events != null) {              

  _events.add(event);

  return;

      }

       Iterator itr = _listeners.iterator();

       // 遍历HotDeployListener,通知它们进行部署.

      while (itr.hasNext()) {

  HotDeployListener listener = (HotDeployListener)itr.next();

  try {

     listener.invokeDeploy(event);

  }  catch (HotDeployException hde) {

     _log.error(StackTraceUtil.getStackTrace(hde));

  }

     }

 }

        // 在liferay portal启动后被调用,此设计的目的主要用于解决portals应用在liferay portal应用之前启动的情况。

 private synchronized void _flushEvents() {

     for (int i = 0; i < _events.size(); i++) {

      HotDeployEvent event = (HotDeployEvent)_events.get(i);

       Iterator itr = _listeners.iterator();

          while (itr.hasNext()) {

  HotDeployListener listener = (HotDeployListener)itr.next();

  try {

     listener.invokeDeploy(event);

  }

  catch (HotDeployException hde) {

     _log.error(StackTraceUtil.getStackTrace(hde));

  }

      }

    }

    _events = null;

 }

 // 注册HotDeployListener

 private void _registerListener(HotDeployListener listener) {

  _listeners.add(listener);

 }

 private List _listeners;

 private List _events;

  }

  这里就有个问题了,HotDeployListener是在哪里加入进来的了?答案是在liferay portal的初始化时加入的。

// liferay portal初始化

  public class MainServlet extends ActionServlet {

      public void init() {        

          // 其它初始化处理......

          try {

                // 执行全局启动事件.

  EventsProcessor.process(PropsUtil.getArray(

   PropsUtil.GLOBAL_STARTUP_EVENTS), true);

  // 执行应用程序启动事件.

  EventsProcessor.process(PropsUtil.getArray(

   PropsUtil.APPLICATION_STARTUP_EVENTS),

     new String[] {_companyId});

  }

  catch (Exception e) {

  _log.error(e);

  }

      PortalInstances.init(_companyId);

      } 

   }

   EventsProcessor是liferay portal中的事件处理器,liferay portal中定义了一系列的事件点,

   像上面的APPLICATION_STARTUP_EVENTS,就是应用程序启动事件点.

   通过配置文件,就可以将我们的自定义事件加入到这些事件点里去执行了。

   关于EventProcessor更详细的内容,将用另外一篇文章来详细介绍,这里只需要知道有两个事件被触发了。

// 全局启动事件。

  public class GlobalStartupAction extends SimpleAction {

      public void run(String[] ids) throws ActionException {

      // JCR 处理...

      // Portal initable

      PortalInitableUtil.flushInitables();

      // Hot deploy

      // 注册layoutTemplate监听器.

      HotDeployUtil.registerListener(new HotDeployLayoutTemplateListener());

      // 注册portlet监听器.

      HotDeployUtil.registerListener(new HotDeployPortletListener());

      // 注册theme监听器.

      HotDeployUtil.registerListener(new HotDeployThemeListener());

      // 清理所有事件.

      HotDeployUtil.flushEvents();

      // Auto deploy 自动部署处理.....

  }

// 部署Portlets

 public class HotDeployPortletListener implements HotDeployListener {

 public void invokeDeploy(HotDeployEvent event) throws HotDeployException {

  String servletContextName = null;

  try {

   // Servlet context

   ServletContext ctx = event.getServletContext();

   servletContextName = ctx.getServletContextName();

   // Company ids

   String[] companyIds = StringUtil.split(

    ctx.getInitParameter("company_id"));

   if ((companyIds.length == 1) && (companyIds[0].equals("*"))) {

    companyIds = PortalInstances.getCompanyIds();

   }

   // Initialize portlets, 初始化portlets

   String[] xmls = new String[] {

    Http.URLtoString(ctx.getResource("/WEB-INF/portlet.xml")),

    Http.URLtoString(ctx.getResource(

     "/WEB-INF/liferay-portlet.xml")),

    Http.URLtoString(ctx.getResource("/WEB-INF/web.xml"))

   };

   List portlets = PortletLocalServiceUtil.initWAR(

    servletContextName, xmls);

   // Class loader, 类装载器

   ClassLoader portletClassLoader = event.getContextClassLoader();

   ctx.setAttribute(

    PortletServlet.PORTLET_CLASS_LOADER, portletClassLoader);

   // portlet context wrapper, portlet上下文包装器.

   boolean strutsBridges = false;

   Iterator itr1 = portlets.iterator();

   while (itr1.hasNext()) {

    Portlet portlet = (Portlet)itr1.next();

    // 构造portlet实例.

    Class portletClass = portletClassLoader.loadClass(

      portlet.getPortletClass());

    javax.portlet.Portlet portletInstance =

     (javax.portlet.Portlet)portletClass.newInstance();

    // 检查是否struts桥接portlet.

    if (ClassUtil.isSubclass(portletClass,

     StrutsPortlet.class.getName())) {

     strutsBridges = true;

    }

    // 构造lucene indexer实例.

    Indexer indexerInstance = null;

    if (Validator.isNotNull(portlet.getIndexerClass())) {

     indexerInstance = (Indexer)portletClassLoader.loadClass(

      portlet.getIndexerClass()).newInstance();

    }

    // 构造scheduler实例.

    Scheduler schedulerInstance = null;

    if (Validator.isNotNull(portlet.getSchedulerClass())) {

     schedulerInstance = (Scheduler)portletClassLoader.loadClass(

      portlet.getSchedulerClass()).newInstance();

    }

    // 验证preferences.

    PreferencesValidator prefsValidator = null;

    if (Validator.isNotNull(portlet.getPreferencesValidator())) {

     prefsValidator =

      (PreferencesValidator)portletClassLoader.loadClass(

       portlet.getPreferencesValidator()).newInstance();

     try {

      if (GetterUtil.getBoolean(PropsUtil.get(

        PropsUtil.PREFERENCE_VALIDATE_ON_STARTUP))) {

       prefsValidator.validate(

        PortletPreferencesSerializer.fromDefaultXML(

         portlet.getDefaultPreferences()));

      }

     }

     catch (Exception e1) {

      _log.warn(

       "Portlet with the name " + portlet.getPortletId() +

        " does not have valid default preferences");

     }

    }

    // 资源处理.

    Map resourceBundles = null;

    if (Validator.isNotNull(portlet.getResourceBundle())) {

     resourceBundles = CollectionFactory.getHashMap();

     Iterator itr2 = portlet.getSupportedLocales().iterator();

     while (itr2.hasNext()) {

      String supportedLocale = (String)itr2.next();

      Locale locale = new Locale(supportedLocale);

      try {

       ResourceBundle resourceBundle =

        ResourceBundle.getBundle(

         portlet.getResourceBundle(), locale,

         portletClassLoader);

       resourceBundles.put(

        locale.getLanguage(), resourceBundle);

      }

      catch (MissingResourceException mre) {

       _log.warn(mre.getMessage());

      }

     }

    }

    // 定制用户特性。

    Map customUserAttributes = CollectionFactory.getHashMap();

    Iterator itr2 =

     portlet.getCustomUserAttributes().entrySet().iterator();

    while (itr2.hasNext()) {

     Map.Entry entry = (Map.Entry)itr2.next();

     String attrCustomClass = (String)entry.getValue();

     customUserAttributes.put(

      attrCustomClass,

      portletClassLoader.loadClass(

       attrCustomClass).newInstance());

    }

    PortletContextWrapper pcw = new PortletContextWrapper(

     portlet.getPortletId(), ctx, portletInstance,

     indexerInstance, schedulerInstance, prefsValidator,

     resourceBundles, customUserAttributes);

    PortletContextPool.put(portlet.getPortletId(), pcw);

   }

   // Struts bridges

   if (strutsBridges) {

    ctx.setAttribute(

     ServletContextProvider.STRUTS_BRIDGES_CONTEXT_PROVIDER,

     new LiferayServletContextProvider());

   }

   // Portlet display,portlet展示处理,显示在portlet添加面板上位置.

   String xml = Http.URLtoString(ctx.getResource(

    "/WEB-INF/liferay-display.xml"));

   PortletCategory newPortletCategory =

    PortletLocalServiceUtil.getWARDisplay(servletContextName, xml);

   for (int i = 0; i < companyIds.length; i++) {

    String companyId = companyIds[i];

    PortletCategory portletCategory =

     (PortletCategory)WebAppPool.get(

      companyId, WebKeys.PORTLET_CATEGORY);

    if (portletCategory != null) {

     portletCategory.merge(newPortletCategory);

    }

    else {

     _log.error(

      "Unable to register portlet for company " + companyId +

       " because it does not exist");

    }

   }

   // Variables

   _vars.put(

    servletContextName, new ObjectValuePair(companyIds, portlets));

   if (_log.isInfoEnabled()) {

    _log.info(

     "Portlets for " + servletContextName +

      " registered successfully");

   }

  }

  catch (Exception e2) {

   throw new HotDeployException(

    "Error registering portlets for " + servletContextName, e2);

  }

 }

 }

关于layoutTemplates和theme的部署这里就不列出了,请自行参考源代码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: