You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

VaadinPortlet.java 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. /*
  2. * Copyright 2000-2016 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.server;
  17. import java.io.IOException;
  18. import java.io.Serializable;
  19. import java.lang.reflect.InvocationTargetException;
  20. import java.lang.reflect.Method;
  21. import java.util.Enumeration;
  22. import java.util.Map;
  23. import java.util.Properties;
  24. import java.util.logging.Level;
  25. import java.util.logging.Logger;
  26. import javax.portlet.ActionRequest;
  27. import javax.portlet.ActionResponse;
  28. import javax.portlet.EventRequest;
  29. import javax.portlet.EventResponse;
  30. import javax.portlet.GenericPortlet;
  31. import javax.portlet.PortalContext;
  32. import javax.portlet.PortletConfig;
  33. import javax.portlet.PortletContext;
  34. import javax.portlet.PortletException;
  35. import javax.portlet.PortletRequest;
  36. import javax.portlet.PortletResponse;
  37. import javax.portlet.RenderRequest;
  38. import javax.portlet.RenderResponse;
  39. import javax.portlet.ResourceRequest;
  40. import javax.portlet.ResourceResponse;
  41. import javax.servlet.http.HttpServletRequest;
  42. import javax.servlet.http.HttpServletRequestWrapper;
  43. import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
  44. import com.liferay.portal.kernel.util.PropsUtil;
  45. import com.vaadin.server.communication.PortletDummyRequestHandler;
  46. import com.vaadin.server.communication.PortletUIInitHandler;
  47. import com.vaadin.ui.UI;
  48. import com.vaadin.util.CurrentInstance;
  49. /**
  50. * Portlet 2.0 base class. This replaces the servlet in servlet/portlet 1.0
  51. * deployments and handles various portlet requests from the browser.
  52. *
  53. * @author Vaadin Ltd
  54. */
  55. public class VaadinPortlet extends GenericPortlet
  56. implements Constants, Serializable {
  57. /**
  58. * Base class for portlet requests that need access to HTTP servlet
  59. * requests.
  60. */
  61. public static abstract class VaadinHttpAndPortletRequest
  62. extends VaadinPortletRequest {
  63. /**
  64. * Constructs a new {@link VaadinHttpAndPortletRequest}.
  65. *
  66. * @since 7.2
  67. * @param request
  68. * {@link PortletRequest} to be wrapped
  69. * @param vaadinService
  70. * {@link VaadinPortletService} associated with this request
  71. */
  72. public VaadinHttpAndPortletRequest(PortletRequest request,
  73. VaadinPortletService vaadinService) {
  74. super(request, vaadinService);
  75. }
  76. private HttpServletRequest originalRequest;
  77. /**
  78. * Returns the original HTTP servlet request for this portlet request.
  79. *
  80. * @since 7.2
  81. * @param request
  82. * {@link PortletRequest} used to
  83. * @return the original HTTP servlet request
  84. */
  85. protected abstract HttpServletRequest getServletRequest(
  86. PortletRequest request);
  87. private HttpServletRequest getOriginalRequest() {
  88. if (originalRequest == null) {
  89. PortletRequest request = getRequest();
  90. originalRequest = getServletRequest(request);
  91. }
  92. return originalRequest;
  93. }
  94. @Override
  95. public String getParameter(String name) {
  96. String parameter = super.getParameter(name);
  97. if (parameter == null && getOriginalRequest() != null) {
  98. parameter = getOriginalRequest().getParameter(name);
  99. }
  100. return parameter;
  101. }
  102. @Override
  103. public String getRemoteAddr() {
  104. if (getOriginalRequest() != null) {
  105. return getOriginalRequest().getRemoteAddr();
  106. } else {
  107. return super.getRemoteAddr();
  108. }
  109. }
  110. @Override
  111. public String getRemoteHost() {
  112. if (getOriginalRequest() != null) {
  113. return getOriginalRequest().getRemoteHost();
  114. } else {
  115. return super.getRemoteHost();
  116. }
  117. }
  118. @Override
  119. public int getRemotePort() {
  120. if (getOriginalRequest() != null) {
  121. return getOriginalRequest().getRemotePort();
  122. } else {
  123. return super.getRemotePort();
  124. }
  125. }
  126. @Override
  127. public String getHeader(String name) {
  128. String header = super.getHeader(name);
  129. if (header == null && getOriginalRequest() != null) {
  130. header = getOriginalRequest().getHeader(name);
  131. }
  132. return header;
  133. }
  134. @Override
  135. public Enumeration<String> getHeaderNames() {
  136. Enumeration<String> headerNames = super.getHeaderNames();
  137. if (headerNames == null && getOriginalRequest() != null) {
  138. headerNames = getOriginalRequest().getHeaderNames();
  139. }
  140. return headerNames;
  141. }
  142. @Override
  143. public Enumeration<String> getHeaders(String name) {
  144. Enumeration<String> headers = super.getHeaders(name);
  145. if (headers == null && getOriginalRequest() != null) {
  146. headers = getOriginalRequest().getHeaders(name);
  147. }
  148. return headers;
  149. }
  150. @Override
  151. public Map<String, String[]> getParameterMap() {
  152. Map<String, String[]> parameterMap = super.getParameterMap();
  153. if (parameterMap == null && getOriginalRequest() != null) {
  154. parameterMap = getOriginalRequest().getParameterMap();
  155. }
  156. return parameterMap;
  157. }
  158. }
  159. /**
  160. * Portlet request for Liferay.
  161. */
  162. public static class VaadinLiferayRequest
  163. extends VaadinHttpAndPortletRequest {
  164. /**
  165. * The PortalUtil class to use. Set to either
  166. * {@link #LIFERAY_6_PORTAL_UTIL} or {@link #LIFERAY_7_PORTAL_UTIL} the
  167. * first time it is needed.
  168. */
  169. private static String portalUtilClass = null;
  170. private static final String LIFERAY_6_PORTAL_UTIL = "com.liferay.portal.util.PortalUtil";
  171. private static final String LIFERAY_7_PORTAL_UTIL = "com.liferay.portal.kernel.util.PortalUtil";
  172. public VaadinLiferayRequest(PortletRequest request,
  173. VaadinPortletService vaadinService) {
  174. super(request, vaadinService);
  175. }
  176. @Override
  177. public String getPortalProperty(String name) {
  178. return PropsUtil.get(name);
  179. }
  180. /**
  181. * Simplified version of what Liferay PortalClassInvoker did. This is
  182. * used because the API of PortalClassInvoker has changed in Liferay
  183. * 6.2.
  184. *
  185. * This simply uses reflection with Liferay class loader. Parameters are
  186. * Strings to avoid static dependencies and to load all classes with
  187. * Liferay's own class loader. Only static utility methods are
  188. * supported.
  189. *
  190. * This method is for internal use only and may change in future
  191. * versions.
  192. *
  193. * @param className
  194. * name of the Liferay class to call
  195. * @param methodName
  196. * name of the method to call
  197. * @param parameterClassName
  198. * name of the parameter class of the method
  199. * @throws Exception
  200. * @return return value of the invoked method
  201. */
  202. private Object invokeStaticLiferayMethod(String className,
  203. String methodName, Object argument, String parameterClassName)
  204. throws Exception {
  205. Thread currentThread = Thread.currentThread();
  206. ClassLoader contextClassLoader = currentThread
  207. .getContextClassLoader();
  208. try {
  209. // this should be available across all Liferay versions with no
  210. // problematic static dependencies
  211. ClassLoader portalClassLoader = PortalClassLoaderUtil
  212. .getClassLoader();
  213. // this is in case the class loading triggers code that
  214. // explicitly
  215. // uses current thread class loader
  216. currentThread.setContextClassLoader(portalClassLoader);
  217. Class<?> targetClass = portalClassLoader.loadClass(className);
  218. Class<?> parameterClass = portalClassLoader
  219. .loadClass(parameterClassName);
  220. Method method = targetClass.getMethod(methodName,
  221. parameterClass);
  222. return method.invoke(null, argument);
  223. } catch (InvocationTargetException ite) {
  224. throw (Exception) ite.getCause();
  225. } finally {
  226. currentThread.setContextClassLoader(contextClassLoader);
  227. }
  228. }
  229. @Override
  230. protected HttpServletRequest getServletRequest(PortletRequest request) {
  231. if (portalUtilClass == null) {
  232. try {
  233. invokeStaticLiferayMethod(LIFERAY_7_PORTAL_UTIL,
  234. "getHttpServletRequest", request,
  235. "javax.portlet.PortletRequest");
  236. portalUtilClass = LIFERAY_7_PORTAL_UTIL;
  237. } catch (Exception e) {
  238. // Liferay 6 or older
  239. portalUtilClass = LIFERAY_6_PORTAL_UTIL;
  240. }
  241. }
  242. try {
  243. // httpRequest = PortalUtil.getHttpServletRequest(request);
  244. HttpServletRequest httpRequest = (HttpServletRequest) invokeStaticLiferayMethod(
  245. portalUtilClass, "getHttpServletRequest", request,
  246. "javax.portlet.PortletRequest");
  247. // httpRequest =
  248. // PortalUtil.getOriginalServletRequest(httpRequest);
  249. httpRequest = (HttpServletRequest) invokeStaticLiferayMethod(
  250. portalUtilClass, "getOriginalServletRequest",
  251. httpRequest, "javax.servlet.http.HttpServletRequest");
  252. return httpRequest;
  253. } catch (Exception e) {
  254. throw new IllegalStateException("Liferay request not detected",
  255. e);
  256. }
  257. }
  258. }
  259. /**
  260. * Portlet request for GateIn.
  261. */
  262. public static class VaadinGateInRequest
  263. extends VaadinHttpAndPortletRequest {
  264. public VaadinGateInRequest(PortletRequest request,
  265. VaadinPortletService vaadinService) {
  266. super(request, vaadinService);
  267. }
  268. @Override
  269. protected HttpServletRequest getServletRequest(PortletRequest request) {
  270. try {
  271. Method getRealReq = request.getClass()
  272. .getMethod("getRealRequest");
  273. HttpServletRequestWrapper origRequest = (HttpServletRequestWrapper) getRealReq
  274. .invoke(request);
  275. return origRequest;
  276. } catch (Exception e) {
  277. throw new IllegalStateException("GateIn request not detected",
  278. e);
  279. }
  280. }
  281. }
  282. /**
  283. * Portlet request for WebSphere Portal.
  284. */
  285. public static class VaadinWebSpherePortalRequest
  286. extends VaadinHttpAndPortletRequest {
  287. public VaadinWebSpherePortalRequest(PortletRequest request,
  288. VaadinPortletService vaadinService) {
  289. super(request, vaadinService);
  290. }
  291. @Override
  292. protected HttpServletRequest getServletRequest(PortletRequest request) {
  293. try {
  294. Class<?> portletUtils = Class.forName(
  295. "com.ibm.ws.portletcontainer.portlet.PortletUtils");
  296. Method getHttpServletRequest = portletUtils.getMethod(
  297. "getHttpServletRequest", PortletRequest.class);
  298. return (HttpServletRequest) getHttpServletRequest.invoke(null,
  299. request);
  300. } catch (Exception e) {
  301. throw new IllegalStateException(
  302. "WebSphere Portal request not detected.");
  303. }
  304. }
  305. }
  306. /**
  307. * Portlet request for WebSphere Portal.
  308. */
  309. public static class VaadinWebLogicPortalRequest
  310. extends VaadinHttpAndPortletRequest {
  311. private static boolean warningLogged = false;
  312. private static Method servletRequestMethod = null;
  313. public VaadinWebLogicPortalRequest(PortletRequest request,
  314. VaadinPortletService vaadinService) {
  315. super(request, vaadinService);
  316. }
  317. @Override
  318. protected HttpServletRequest getServletRequest(PortletRequest request) {
  319. try {
  320. if (servletRequestMethod == null) {
  321. Class<?> portletRequestClass = Class.forName(
  322. "com.bea.portlet.container.PortletRequestImpl");
  323. servletRequestMethod = portletRequestClass
  324. .getDeclaredMethod("getInternalRequest");
  325. servletRequestMethod.setAccessible(true);
  326. }
  327. return (HttpServletRequest) servletRequestMethod
  328. .invoke(request);
  329. } catch (Exception e) {
  330. if (!warningLogged) {
  331. warningLogged = true;
  332. getLogger().log(Level.WARNING,
  333. "Could not determine underlying servlet request for WebLogic Portal portlet request",
  334. e);
  335. }
  336. return null;
  337. }
  338. }
  339. }
  340. /**
  341. * @deprecated As of 7.0. Will likely change or be removed in a future
  342. * version
  343. */
  344. @Deprecated
  345. public static final String RESOURCE_URL_ID = "APP";
  346. /**
  347. * This portlet parameter is used to add styles to the main element. E.g
  348. * "height:500px" generates a style="height:500px" to the main element.
  349. *
  350. * @deprecated As of 7.0. Will likely change or be removed in a future
  351. * version
  352. */
  353. @Deprecated
  354. public static final String PORTLET_PARAMETER_STYLE = "style";
  355. /**
  356. * This portal parameter is used to define the name of the Vaadin theme that
  357. * is used for all Vaadin applications in the portal.
  358. *
  359. * @deprecated As of 7.0. Will likely change or be removed in a future
  360. * version
  361. */
  362. @Deprecated
  363. public static final String PORTAL_PARAMETER_VAADIN_THEME = "vaadin.theme";
  364. /**
  365. * @deprecated As of 7.0. Will likely change or be removed in a future
  366. * version
  367. */
  368. @Deprecated
  369. public static final String WRITE_AJAX_PAGE_SCRIPT_WIDGETSET_SHOULD_WRITE = "writeAjaxPageScriptWidgetsetShouldWrite";
  370. // TODO some parts could be shared with AbstractApplicationServlet
  371. // TODO Can we close the application when the portlet is removed? Do we know
  372. // when the portlet is removed?
  373. private VaadinPortletService vaadinService;
  374. @Override
  375. public void init(PortletConfig config) throws PortletException {
  376. CurrentInstance.clearAll();
  377. super.init(config);
  378. Properties initParameters = new Properties();
  379. // Read default parameters from the context
  380. final PortletContext context = config.getPortletContext();
  381. for (final Enumeration<String> e = context.getInitParameterNames(); e
  382. .hasMoreElements();) {
  383. final String name = e.nextElement();
  384. initParameters.setProperty(name, context.getInitParameter(name));
  385. }
  386. // Override with application settings from portlet.xml
  387. for (final Enumeration<String> e = config.getInitParameterNames(); e
  388. .hasMoreElements();) {
  389. final String name = e.nextElement();
  390. initParameters.setProperty(name, config.getInitParameter(name));
  391. }
  392. DeploymentConfiguration deploymentConfiguration = createDeploymentConfiguration(
  393. initParameters);
  394. try {
  395. vaadinService = createPortletService(deploymentConfiguration);
  396. } catch (ServiceException e) {
  397. throw new PortletException("Could not initialized VaadinPortlet",
  398. e);
  399. }
  400. // Sets current service even though there are no request and response
  401. vaadinService.setCurrentInstances(null, null);
  402. portletInitialized();
  403. CurrentInstance.clearAll();
  404. }
  405. protected void portletInitialized() throws PortletException {
  406. }
  407. protected DeploymentConfiguration createDeploymentConfiguration(
  408. Properties initParameters) {
  409. return new DefaultDeploymentConfiguration(getClass(), initParameters);
  410. }
  411. protected VaadinPortletService createPortletService(
  412. DeploymentConfiguration deploymentConfiguration)
  413. throws ServiceException {
  414. VaadinPortletService service = new VaadinPortletService(this,
  415. deploymentConfiguration);
  416. service.init();
  417. return service;
  418. }
  419. /**
  420. * @author Vaadin Ltd
  421. *
  422. * @deprecated As of 7.0. This is no longer used and only provided for
  423. * backwards compatibility. Each {@link RequestHandler} can
  424. * individually decide whether it wants to handle a request or
  425. * not.
  426. */
  427. @Deprecated
  428. protected enum RequestType {
  429. FILE_UPLOAD, UIDL, RENDER, STATIC_FILE, APP, DUMMY, EVENT, ACTION, UNKNOWN, BROWSER_DETAILS, PUBLISHED_FILE, HEARTBEAT;
  430. }
  431. /**
  432. * @param vaadinRequest
  433. * @return
  434. *
  435. * @deprecated As of 7.0. This is no longer used and only provided for
  436. * backwards compatibility. Each {@link RequestHandler} can
  437. * individually decide whether it wants to handle a request or
  438. * not.
  439. */
  440. @Deprecated
  441. protected RequestType getRequestType(VaadinPortletRequest vaadinRequest) {
  442. PortletRequest request = vaadinRequest.getPortletRequest();
  443. if (request instanceof RenderRequest) {
  444. return RequestType.RENDER;
  445. } else if (request instanceof ResourceRequest) {
  446. if (ServletPortletHelper.isUIDLRequest(vaadinRequest)) {
  447. return RequestType.UIDL;
  448. } else if (PortletUIInitHandler.isUIInitRequest(vaadinRequest)) {
  449. return RequestType.BROWSER_DETAILS;
  450. } else if (ServletPortletHelper
  451. .isFileUploadRequest(vaadinRequest)) {
  452. return RequestType.FILE_UPLOAD;
  453. } else if (ServletPortletHelper
  454. .isPublishedFileRequest(vaadinRequest)) {
  455. return RequestType.PUBLISHED_FILE;
  456. } else if (ServletPortletHelper.isAppRequest(vaadinRequest)) {
  457. return RequestType.APP;
  458. } else if (ServletPortletHelper.isHeartbeatRequest(vaadinRequest)) {
  459. return RequestType.HEARTBEAT;
  460. } else if (PortletDummyRequestHandler
  461. .isDummyRequest(vaadinRequest)) {
  462. return RequestType.DUMMY;
  463. } else {
  464. return RequestType.STATIC_FILE;
  465. }
  466. } else if (request instanceof ActionRequest) {
  467. return RequestType.ACTION;
  468. } else if (request instanceof EventRequest) {
  469. return RequestType.EVENT;
  470. }
  471. return RequestType.UNKNOWN;
  472. }
  473. /**
  474. * @param request
  475. * @param response
  476. * @throws PortletException
  477. * @throws IOException
  478. *
  479. * @deprecated As of 7.0. Will likely change or be removed in a future
  480. * version
  481. */
  482. @Deprecated
  483. protected void handleRequest(PortletRequest request,
  484. PortletResponse response) throws PortletException, IOException {
  485. CurrentInstance.clearAll();
  486. try {
  487. getService().handleRequest(createVaadinRequest(request),
  488. createVaadinResponse(response));
  489. } catch (ServiceException e) {
  490. throw new PortletException(e);
  491. }
  492. }
  493. /**
  494. * Wraps the request in a (possibly portal specific) Vaadin portlet request.
  495. *
  496. * @param request
  497. * The original PortletRequest
  498. * @return A wrapped version of the PortletRequest
  499. */
  500. protected VaadinPortletRequest createVaadinRequest(PortletRequest request) {
  501. PortalContext portalContext = request.getPortalContext();
  502. String portalInfo = portalContext.getPortalInfo().toLowerCase().trim();
  503. VaadinPortletService service = getService();
  504. if (portalInfo.contains("gatein")) {
  505. return new VaadinGateInRequest(request, service);
  506. }
  507. if (portalInfo.contains("liferay")) {
  508. return new VaadinLiferayRequest(request, service);
  509. }
  510. if (portalInfo.contains("websphere portal")) {
  511. return new VaadinWebSpherePortalRequest(request, service);
  512. }
  513. if (portalInfo.contains("weblogic portal")) {
  514. return new VaadinWebLogicPortalRequest(request, service);
  515. }
  516. return new VaadinPortletRequest(request, service);
  517. }
  518. private VaadinPortletResponse createVaadinResponse(
  519. PortletResponse response) {
  520. return new VaadinPortletResponse(response, getService());
  521. }
  522. protected VaadinPortletService getService() {
  523. return vaadinService;
  524. }
  525. @Override
  526. public void processEvent(EventRequest request, EventResponse response)
  527. throws PortletException, IOException {
  528. handleRequest(request, response);
  529. }
  530. @Override
  531. public void processAction(ActionRequest request, ActionResponse response)
  532. throws PortletException, IOException {
  533. handleRequest(request, response);
  534. }
  535. @Override
  536. protected void doDispatch(RenderRequest request, RenderResponse response)
  537. throws PortletException, IOException {
  538. try {
  539. // try to let super handle - it'll call methods annotated for
  540. // handling, the default doXYZ(), or throw if a handler for the mode
  541. // is not found
  542. super.doDispatch(request, response);
  543. } catch (PortletException e) {
  544. if (e.getCause() == null) {
  545. // No cause interpreted as 'unknown mode' - pass that trough
  546. // so that the application can handle
  547. handleRequest(request, response);
  548. } else {
  549. // Something else failed, pass on
  550. throw e;
  551. }
  552. }
  553. }
  554. @Override
  555. public void serveResource(ResourceRequest request,
  556. ResourceResponse response) throws PortletException, IOException {
  557. handleRequest(request, response);
  558. }
  559. @Override
  560. public void destroy() {
  561. super.destroy();
  562. getService().destroy();
  563. }
  564. private static final Logger getLogger() {
  565. return Logger.getLogger(VaadinPortlet.class.getName());
  566. }
  567. /**
  568. * Gets the currently used Vaadin portlet. The current portlet is
  569. * automatically defined when processing requests related to the service
  570. * (see {@link ThreadLocal}) and in {@link VaadinSession#access(Command)}
  571. * and {@link UI#access(Command)}. In other cases, (e.g. from background
  572. * threads, the current service is not automatically defined.
  573. *
  574. * The current portlet is derived from the current service using
  575. * {@link VaadinService#getCurrent()}
  576. *
  577. * @return the current vaadin portlet instance if available, otherwise
  578. * <code>null</code>
  579. *
  580. * @since 7.0
  581. */
  582. public static VaadinPortlet getCurrent() {
  583. VaadinService vaadinService = CurrentInstance.get(VaadinService.class);
  584. if (vaadinService instanceof VaadinPortletService) {
  585. VaadinPortletService vps = (VaadinPortletService) vaadinService;
  586. return vps.getPortlet();
  587. } else {
  588. return null;
  589. }
  590. }
  591. }