/** * Provides services for the space gadget to display a user's spaces and pending spaces. * * @anchor SpacesRestService */ @Path("{portalName}/social/spaces") public class SpacesRestService implements ResourceContainer { private SpaceService _spaceService; private IdentityManager _identityManager; /** Confirmed Status information */ private static final String CONFIRMED_STATUS = "confirmed"; /** Pending Status information */ private static final String PENDING_STATUS = "pending"; /** Incoming Status information */ private static final String INCOMING_STATUS = "incoming"; /** Public Status information */ private static final String ALL_SPACES_STATUS = "all_spaces"; private String portalContainerName; /** * Qualified name path for rendering url. * * @since 1.2.2 */ private static final QualifiedName PATH = QualifiedName.create("gtn", "path"); /** * Qualified name path for rendering url. * * @since 1.2.9 */ private static final QualifiedName LANG = QualifiedName.create("gtn", "lang"); /** * Qualified name site type for rendering url. * * @since 1.2.2 */ private static final QualifiedName REQUEST_SITE_TYPE = QualifiedName.create("gtn", "sitetype"); /** * Qualified name handler for rendering url. * * @since 1.2.2 */ private static final QualifiedName REQUEST_HANDLER = QualifiedName.create("gtn", "handler"); /** * Qualified name site name for rendering url. * * @since 1.2.2 */ private static final QualifiedName REQUEST_SITE_NAME = QualifiedName.create("gtn", "sitename"); private static final String ALL_SPACES = "all-spaces"; /** constructor */ public SpacesRestService() {} /** * Gets the current user's spaces and pending spaces. * * @param uriInfo The requested URI information. * @param portalName The name of the current container. * @param format The format of the returned result. * @anchor SpacesRestService.showMySpaceList * @return response * @throws Exception @LevelAPI Platform * @deprecated Deprecated from 4.3.x. Replaced by a new API {@link * UserRestResourcesV1#getSpacesOfUser(org.exoplatform.social.rest.impl.user.UriInfo, String, * int, int, boolean, String)} */ @GET @Path("mySpaces/show.{format}") public Response showMySpaceList( @Context UriInfo uriInfo, @PathParam("portalName") String portalName, @PathParam("format") String format) throws Exception { MediaType mediaType = Util.getMediaType(format); ConversationState state = ConversationState.getCurrent(); portalContainerName = portalName; String userId = null; if (state != null) { userId = state.getIdentity().getUserId(); } Identity identity = getIdentityManager().getOrCreateIdentity(OrganizationIdentityProvider.NAME, userId, false); if (identity == null) { userId = Util.getViewerId(uriInfo); } SpaceList mySpaceList = showMySpaceList(userId); this.fillUrlAllSpaces(mySpaceList, portalName); return Util.getResponse(mySpaceList, uriInfo, mediaType, Response.Status.OK); } /** * Provides a way to get the latest spaces ordered by last access and to be able to filter spaces, * based on the application Id in the spaces. * * @param uriInfo The requested URI information. * @param portalName The portal container name. * @param format The format of the returned result, for example, JSON, or XML. * @param offset Specifies the staring point of the returned results. It must be greater than or * equal to 0. * @param limit Specifies the ending point of the returned results. It must be less than or equal * to 10. * @param appId The application Id which is contained in spaces to filter, such as, Wiki, * Discussion, Documents, Agenda and more. * @authentication * @request GET: * http://localhost:8080/rest/private/social/spaces/lastVisitedSpace/list.json?appId=Wiki&offset=0&limit=10 * @response { "spaces":[ * {"groupId":"/spaces/space_2","spaceUrl":null,"name":"space_2","displayName":"space * 2","url":"space_2"}, * {"groupId":"/spaces/space_1","spaceUrl":null,"name":"space_1","displayName":"space * 1","url":"space_1"} ], "moreSpacesUrl":null } * @return the response @LevelAPI Platform * @anchor SpacesRestService.getLastVisitedSpace */ @GET @Path("lastVisitedSpace/list.{format}") public Response getLastVisitedSpace( @Context UriInfo uriInfo, @PathParam("portalName") String portalName, @PathParam("format") String format, @QueryParam("appId") String appId, @QueryParam("offset") int offset, @QueryParam("limit") int limit) throws Exception { checkAuthenticatedRequest(); MediaType mediaType = Util.getMediaType(format, new String[] {format}); ConversationState state = ConversationState.getCurrent(); portalContainerName = portalName; String userId = null; if (state != null) { userId = state.getIdentity().getUserId(); } Identity identity = getIdentityManager().getOrCreateIdentity(OrganizationIdentityProvider.NAME, userId, false); if (identity == null) { userId = Util.getViewerId(uriInfo); } // int newLimit = Math.min(limit, 100); int newOffset = 0; if (offset > 0) { newOffset = Math.min(offset, newLimit); } else { newOffset = 0; } // String newAppId = null; if (appId != null && appId.trim().length() > 0) { newAppId = appId; } SpaceList mySpaceList = getLastVisitedSpace(userId, newAppId, newOffset, newLimit); return Util.getResponse(mySpaceList, uriInfo, mediaType, Response.Status.OK); } /** * Gets a user's pending spaces. * * @param uriInfo The requested URI information. * @param portalName The portal container name. * @param format The format of the returned result, for example, JSON, or XML. * @anchor SpacesRestService.showPendingSpaceList * @return response * @throws Exception @LevelAPI Platform */ @GET @Path("pendingSpaces/show.{format}") public Response showPendingSpaceList( @Context UriInfo uriInfo, @PathParam("portalName") String portalName, @PathParam("format") String format) throws Exception { MediaType mediaType = Util.getMediaType(format); String userId = ConversationState.getCurrent().getIdentity().getUserId(); portalContainerName = portalName; if (!userId.equals(Util.getViewerId(uriInfo))) { return null; } SpaceList pendingSpaceList = showPendingSpaceList(userId); return Util.getResponse(pendingSpaceList, uriInfo, mediaType, Response.Status.OK); } /** * Suggests the space's name for searching. * * @param uriInfo The requested URI information. * @param portalName The name of portal. * @param conditionToSearch The input information to search. * @param typeOfRelation The type of relationship of the user and the space. * @param userId The Id of current user. * @param format The format of the returned result, for example, JSON, or XML. * @return * @throws Exception @LevelAPI Platform * @anchor SpacesRestService.suggestSpacenames * @deprecated Deprecated from 4.3.x. Replaced by a new API {@link * SpaceRestResourcesV1#getSpaces(org.exoplatform.social.rest.impl.space.UriInfo, String, int, * int, boolean, String)} */ @GET @Path("suggest.{format}") public Response suggestSpacenames( @Context UriInfo uriInfo, @PathParam("portalName") String portalName, @QueryParam("conditionToSearch") String conditionToSearch, @QueryParam("typeOfRelation") String typeOfRelation, @QueryParam("currentUser") String userId, @PathParam("format") String format) throws Exception { MediaType mediaType = Util.getMediaType(format); SpaceNameList nameList = new SpaceNameList(); portalContainerName = portalName; SpaceService spaceSrv = getSpaceService(); SpaceListAccess listAccess = spaceSrv.getVisibleSpacesWithListAccess(userId, new SpaceFilter(conditionToSearch)); List<Space> spaces = Arrays.asList(listAccess.load(0, 10)); for (Space space : spaces) { if (ALL_SPACES_STATUS.equals(typeOfRelation)) { nameList.addName(space.getDisplayName()); } else { if (PENDING_STATUS.equals(typeOfRelation) && (spaceSrv.isPending(space, userId))) { nameList.addName(space.getDisplayName()); continue; } else if (INCOMING_STATUS.equals(typeOfRelation) && (spaceSrv.isInvited(space, userId))) { nameList.addName(space.getDisplayName()); continue; } else if (CONFIRMED_STATUS.equals(typeOfRelation) && (spaceSrv.isMember(space, userId))) { nameList.addName(space.getDisplayName()); continue; } } } return Util.getResponse(nameList, uriInfo, mediaType, Response.Status.OK); } /** * List that contains space from space service.<br> * Need this class for converter from rest service. */ @XmlRootElement public static class SpaceList { private String moreSpacesUrl; private List<SpaceRest> _spaces; /** * sets space list * * @param spaces space list */ public void setSpaces(List<SpaceRest> spaces) { _spaces = spaces; } /** * gets space list * * @return space list */ public List<SpaceRest> getSpaces() { return _spaces; } /** * adds space to space list * * @param space * @see Space */ public void addSpace(SpaceRest space) { if (_spaces == null) { _spaces = new LinkedList<SpaceRest>(); } _spaces.add(space); } /** * Get the url of all spaces. * * @return * @since 1.2.9 */ public String getMoreSpacesUrl() { return moreSpacesUrl; } /** * Set the url of all spaces. * * @param allSpacesUrl * @since 1.2.9 */ public void setMoreSpacesUrl(String allSpacesUrl) { moreSpacesUrl = allSpacesUrl; } } @XmlRootElement public static class SpaceNameList { private List<String> _names; /** * Sets space name list * * @param space name list */ public void setNames(List<String> names) { this._names = names; } /** * Gets space name list * * @return space name list */ public List<String> getNames() { return _names; } /** * Add name to space name list * * @param space name */ public void addName(String name) { if (_names == null) { _names = new ArrayList<String>(); } _names.add(name); } } /** * shows my spaceList by userId * * @param userId * @return spaceList * @see SpaceList */ private SpaceList showMySpaceList(String userId) { SpaceList spaceList = new SpaceList(); _spaceService = getSpaceService(); List<Space> mySpaces = null; List<SpaceRest> mySpacesRest = new ArrayList<SpaceRest>(); try { mySpaces = _spaceService.getSpaces(userId); for (Space space : mySpaces) { SpaceRest spaceRest = new SpaceRest(space); mySpacesRest.add(spaceRest); } // fix for issue SOC-2039, sets the space url with new navigation controller Router router = this.getRouter(this.getConfigurationPath()); this.fillSpacesURI(mySpacesRest, router); } catch (SpaceException e) { throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } catch (Exception e) { throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } spaceList.setSpaces(mySpacesRest); return spaceList; } /** * get my spaceList by userId which user is last visited * * @param userId * @param appId * @param limit * @return */ private SpaceList getLastVisitedSpace(String userId, String appId, int offset, int limit) { SpaceList spaceList = new SpaceList(); _spaceService = getSpaceService(); List<Space> mySpaces = null; try { mySpaces = _spaceService.getLastAccessedSpace(userId, appId, offset, limit); SpaceRest spaceRest; for (Space space : mySpaces) { spaceRest = new SpaceRest(space); spaceList.addSpace(spaceRest); } } catch (SpaceException e) { throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } catch (Exception e) { throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } return spaceList; } /** * shows pending spaceList by userId * * @param userId * @return spaceList * @see SpaceList */ private SpaceList showPendingSpaceList(String userId) { SpaceList spaceList = new SpaceList(); _spaceService = getSpaceService(); List<Space> pendingSpaces; List<SpaceRest> pendingSpacesRest = new ArrayList<SpaceRest>(); try { pendingSpaces = _spaceService.getPendingSpaces(userId); for (Space space : pendingSpaces) { SpaceRest spaceRest = new SpaceRest(space); pendingSpacesRest.add(spaceRest); } } catch (SpaceException e) { throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } spaceList.setSpaces(pendingSpacesRest); return spaceList; } /** * Fill url for more spaces. * * @param spaceList * @param portalOwner * @since 1.2.9 */ private void fillUrlAllSpaces(SpaceList spaceList, String portalOwner) { try { Router router = this.getRouter(this.getConfigurationPath()); Map<QualifiedName, String> qualifiedName = new HashedMap(); qualifiedName.put(REQUEST_HANDLER, "portal"); qualifiedName.put(REQUEST_SITE_TYPE, "portal"); qualifiedName.put(LANG, ""); StringBuilder urlBuilder = new StringBuilder(); qualifiedName.put(REQUEST_SITE_NAME, portalOwner); qualifiedName.put(PATH, ALL_SPACES); router.render(qualifiedName, new URIWriter(urlBuilder)); spaceList.setMoreSpacesUrl(urlBuilder.toString()); } catch (Exception e) { throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } } /** * gets spaceService * * @return spaceService * @see SpaceService */ private SpaceService getSpaceService() { return (SpaceService) getPortalContainer().getComponentInstanceOfType(SpaceService.class); } /** * gets identityManager * * @return */ private IdentityManager getIdentityManager() { if (_identityManager == null) { _identityManager = (IdentityManager) getPortalContainer().getComponentInstanceOfType(IdentityManager.class); } return _identityManager; } private PortalContainer getPortalContainer() { return (PortalContainer) ExoContainerContext.getContainerByName(portalContainerName); } /** * Fills the spaces uri. * * @param mySpaces * @param router * @since 1.2.2 */ @SuppressWarnings("unchecked") private void fillSpacesURI(List<SpaceRest> mySpaces, Router router) { try { Map<QualifiedName, String> qualifiedName = new HashedMap(); qualifiedName.put(REQUEST_HANDLER, "portal"); qualifiedName.put(REQUEST_SITE_TYPE, "group"); for (SpaceRest space : mySpaces) { StringBuilder urlBuilder = new StringBuilder(); qualifiedName.put(REQUEST_SITE_NAME, space.getGroupId()); qualifiedName.put(PATH, space.getUrl()); router.render(qualifiedName, new URIWriter(urlBuilder)); space.setSpaceUrl(urlBuilder.toString()); } } catch (Exception e) { throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR); } } /** * Gets the configuration path of file controller.xml * * @return * @since 1.2.2 */ private String getConfigurationPath() { PortalContainer portalContainer = this.getPortalContainer(); WebAppController webAppController = (WebAppController) portalContainer.getComponentInstanceOfType(WebAppController.class); return webAppController.getConfigurationPath(); } /** * Gets the router from path of file controller.xml * * @param path * @return * @throws IOException * @throws RouterConfigException * @since 1.2.2 */ private Router getRouter(String path) throws IOException, RouterConfigException { File f = new File(path); if (!f.exists()) { throw new MalformedURLException("Could not resolve path " + path); } if (!f.isFile()) { throw new MalformedURLException("Could not resolve path " + path + " to a valid file"); } return this.getRouter(f.toURI().toURL()); } /** * Gets the router from url. * * @param url * @return * @throws RouterConfigException * @throws IOException * @since 1.2.2 */ private Router getRouter(URL url) throws RouterConfigException, IOException { InputStream in = url.openStream(); try { ControllerDescriptor routerDesc = new DescriptorBuilder().build(in); return new Router(routerDesc); } finally { Safe.close(in); } } }
/** * Append a path, creates the necessary routes and returns the last route added. * * @param pathParamDescriptors the path param descriptors * @param path the path to append * @return the last route added */ private Route append(Map<QualifiedName, PathParamDescriptor> pathParamDescriptors, String path) throws MalformedRouteException { if (path.length() == 0 || path.charAt(0) != '/') { throw new MalformedRouteException(); } // int pos = path.length(); int level = 0; List<Integer> start = new ArrayList<Integer>(); List<Integer> end = new ArrayList<Integer>(); for (int i = 1; i < path.length(); i++) { char c = path.charAt(i); if (c == '{') { if (level++ == 0) { start.add(i); } } else if (c == '}') { if (--level == 0) { end.add(i); } } else if (c == '/') { if (level == 0) { pos = i; break; } } } // Route next; if (start.isEmpty()) { String segment = path.substring(1, pos); SegmentRoute route = new SegmentRoute(router, segment); add(route); next = route; } else { if (start.size() == end.size()) { PatternBuilder builder = new PatternBuilder(); builder.expr("^").expr('/'); List<String> chunks = new ArrayList<String>(); List<PathParam> parameterPatterns = new ArrayList<PathParam>(); // int previous = 1; for (int i = 0; i < start.size(); i++) { builder.litteral(path, previous, start.get(i)); chunks.add(path.substring(previous, start.get(i))); String parameterName = path.substring(start.get(i) + 1, end.get(i)); // QualifiedName parameterQName = QualifiedName.parse(parameterName); // Now get path param metadata PathParamDescriptor parameterDescriptor = pathParamDescriptors.get(parameterQName); // PathParam param; if (parameterDescriptor != null) { param = PathParam.create(parameterDescriptor, router); } else { param = PathParam.create(parameterQName, router); } // Append routing regex to the route regex surrounded by a non capturing regex // to isolate routingRegex like a|b or a(.)b builder.expr("(?:").expr(param.routingRegex).expr(")"); // Add the path param with the rendering regex parameterPatterns.add(param); previous = end.get(i) + 1; } // builder.litteral(path, previous, pos); // We want to satisfy one of the following conditions // - the next char after the matched expression is '/' // - the expression matched until the end // - the match expression is the '/' expression builder.expr("(?:(?<=^/)|(?=/)|$)"); // chunks.add(path.substring(previous, pos)); PatternRoute route = new PatternRoute(router, router.compile(builder.build()), parameterPatterns, chunks); // Wire add(route); // next = route; } else { throw new UnsupportedOperationException("Report error"); } } // if (pos < path.length()) { return next.append(pathParamDescriptors, path.substring(pos)); } else { return next; } }
/** @author <a href="mailto:[email protected]">Julien Viet</a> */ public class ResourceRequestHandler extends WebRequestHandler { public static final String IF_MODIFIED_SINCE = "If-Modified-Since"; public static final String LAST_MODIFIED = "Last-Modified"; /** . */ private static String PATH = "META-INF/maven/org.exoplatform.portal/exo.portal.component.web.resources/pom.properties"; /** . */ private static final Logger log = LoggerFactory.getLogger(ResourceRequestHandler.class); /** . */ public static final String VERSION; static { // Detecting version from maven properties // empty value is ok String version = ""; URL url = ResourceRequestHandler.class.getClassLoader().getResource(PATH); if (url != null) { log.debug("Loading resource serving version from " + url); InputStream in = null; try { in = url.openStream(); Properties props = new Properties(); props.load(in); version = props.getProperty("version"); } catch (IOException e) { log.error("Could not read properties from " + url, e); } finally { IOTools.safeClose(in); } } // log.info("Use version \"" + version + "\" for resource serving"); VERSION = version; } /** . */ public static final QualifiedName VERSION_QN = QualifiedName.create("gtn", "version"); /** . */ public static final QualifiedName RESOURCE_QN = QualifiedName.create("gtn", "resource"); /** . */ public static final QualifiedName SCOPE_QN = QualifiedName.create("gtn", "scope"); /** . */ public static final QualifiedName MODULE_QN = QualifiedName.create("gtn", "module"); /** . */ public static final QualifiedName COMPRESS_QN = QualifiedName.create("gtn", "compress"); /** . */ public static final QualifiedName LANG_QN = QualifiedName.create("gtn", "lang"); /** . */ private final FutureMap<ScriptKey, ScriptResult, ControllerContext> cache; public ResourceRequestHandler() { this.cache = new FutureMap<ScriptKey, ScriptResult, ControllerContext>(new ScriptLoader()); } @Override public String getHandlerName() { return "script"; } @Override public boolean execute(ControllerContext context) throws Exception { String resourceParam = context.getParameter(RESOURCE_QN); String scopeParam = context.getParameter(SCOPE_QN); // if (scopeParam != null && resourceParam != null) { String compressParam = context.getParameter(COMPRESS_QN); String lang = context.getParameter(LANG_QN); String moduleParam = context.getParameter(MODULE_QN); // Locale locale = null; if (lang != null && lang.length() > 0) { locale = I18N.parseTagIdentifier(lang); } // ResourceScope scope; try { scope = ResourceScope.valueOf(ResourceScope.class, scopeParam); } catch (IllegalArgumentException e) { HttpServletResponse response = context.getResponse(); String msg = "Unrecognized scope " + scopeParam; log.error(msg); response.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); return true; } // ResourceId resource = new ResourceId(scope, resourceParam); ScriptKey key = new ScriptKey(resource, moduleParam, "min".equals(compressParam), locale); // ScriptResult result = cache.get(context, key); HttpServletResponse response = context.getResponse(); HttpServletRequest request = context.getRequest(); // if (result instanceof ScriptResult.Resolved) { ScriptResult.Resolved resolved = (ScriptResult.Resolved) result; // Content type + charset response.setContentType("text/javascript"); response.setCharacterEncoding("UTF-8"); // One hour caching // make this configurable later response.setHeader("Cache-Control", "max-age:3600"); response.setDateHeader("Expires", System.currentTimeMillis() + 3600 * 1000); // Set content length response.setContentLength(resolved.bytes.length); long ifModifiedSince = request.getDateHeader(IF_MODIFIED_SINCE); if (resolved.isModified(ifModifiedSince)) { response.setDateHeader(ResourceRequestFilter.LAST_MODIFIED, resolved.lastModified); // Send bytes ServletOutputStream out = response.getOutputStream(); try { out.write(resolved.bytes); } finally { Safe.close(out); } } else { response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } else if (result instanceof ScriptResult.Error) { ScriptResult.Error error = (ScriptResult.Error) result; log.error("Could not render script " + key + "\n:" + error.message); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } else { String msg = "Resource " + key + " cannot be found"; log.error(msg); response.sendError(HttpServletResponse.SC_NOT_FOUND, msg); } } else { HttpServletResponse response = context.getResponse(); String msg = "Missing scope or resource param"; log.error(msg); response.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); } // return true; } @Override protected boolean getRequiresLifeCycle() { return false; } }