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

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