public static boolean createLink( Content content, String link, org.sakaiproject.nakamura.api.lite.Session session) throws org.sakaiproject.nakamura.api.lite.accesscontrol.AccessDeniedException, StorageClientException { String userId = session.getUserId(); if (User.ANON_USER.equals(userId)) { throw new org.sakaiproject.nakamura.api.lite.accesscontrol.AccessDeniedException( Security.ZONE_CONTENT, link, "Cant create a link", userId); } ContentManager contentManager = session.getContentManager(); Content linkNode = contentManager.get(link); if (linkNode == null) { linkNode = new Content( link, ImmutableMap.of( JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY, (Object) RT_SAKAI_LINK, SAKAI_LINK, content.getPath())); } else { linkNode.setProperty(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY, RT_SAKAI_LINK); linkNode.setProperty(SAKAI_LINK, content.getPath()); } contentManager.update(linkNode); return true; }
/** * {@inheritDoc} * * @see * org.sakaiproject.nakamura.api.personal.PersonalTrackingStore#recordActivity(java.lang.String, * java.lang.String, java.lang.String, java.lang.String, java.util.Date) */ public void recordActivity( String resourceId, String resourceType, String activityType, String userId, Calendar timestamp) { Session session = null; try { session = repository.loginAdministrative(); final ContentManager cm = session.getContentManager(); final String trackingNodePath = "/activity/" + resourceType + "/" + resourceId; Content trackingNode = null; if (cm.exists(trackingNodePath)) { trackingNode = cm.get(trackingNodePath); } else { trackingNode = new Content(trackingNodePath, new HashMap<String, Object>()); } if (!trackingNode.hasProperty("count")) { trackingNode.setProperty("count", BigDecimal.ZERO); } if (!trackingNode.hasProperty("sling:resourceType")) { trackingNode.setProperty("sling:resourceType", "sakai/resource-activity"); } final String generatedNodeName = Base64.encodeBase64URLSafeString(asShorterByteArray(UUID.randomUUID())); final String activityNodePath = trackingNodePath + "/" + generatedNodeName; Content activityNode = null; if (cm.exists(activityNodePath)) { activityNode = cm.get(activityNodePath); } else { activityNode = new Content(activityNodePath, new HashMap<String, Object>()); } BigDecimal activityCount = (BigDecimal) trackingNode.getProperty("count"); activityNode.setProperty("sling:resourceType", "sakai/resource-update"); trackingNode.setProperty("count", activityCount.add(BigDecimal.ONE)); activityNode.setProperty("resourceId", resourceId); activityNode.setProperty("resourcetype", resourceType); activityNode.setProperty("activitytype", activityType); activityNode.setProperty("timestamp", timestamp); activityNode.setProperty("userid", userId); cm.update(activityNode); cm.update(trackingNode); } catch (AccessDeniedException e) { LOG.error(e.getLocalizedMessage(), e); } catch (StorageClientException e) { LOG.error(e.getLocalizedMessage(), e); } finally { if (session != null) { try { session.logout(); } catch (ClientPoolException e) { LOG.error(e.getLocalizedMessage(), e); throw new IllegalStateException(e); } } } }
private void updateContentMembers( Session session, Content content, Set<String> viewerSet, Set<String> managerSet, Set<String> editorSet) throws StorageClientException, AccessDeniedException { content.setProperty( POOLED_CONTENT_USER_VIEWER, viewerSet.toArray(new String[viewerSet.size()])); content.setProperty( POOLED_CONTENT_USER_MANAGER, managerSet.toArray(new String[managerSet.size()])); content.setProperty( POOLED_CONTENT_USER_EDITOR, editorSet.toArray(new String[editorSet.size()])); LOGGER.debug( "Set Managers to {}", Arrays.toString(managerSet.toArray(new String[managerSet.size()]))); LOGGER.debug( "Set Editors to {}", Arrays.toString(editorSet.toArray(new String[editorSet.size()]))); LOGGER.debug( "Set Viewers to {}", Arrays.toString(viewerSet.toArray(new String[managerSet.size()]))); session.getContentManager().update(content); }
private void saveMigratorSequence( SessionImpl session, DependencySequence migratorDependencySequence) throws AccessDeniedException, StorageClientException { Content runMigrators = session.getContentManager().get(SYSTEM_MIGRATION_CONTENT_ITEM); String ts = String.valueOf(System.currentTimeMillis()); int i = 0; if (runMigrators == null) { Builder<String, Object> b = ImmutableMap.builder(); for (PropertyMigrator pm : migratorDependencySequence) { b.put(pm.getName(), ts + ";" + i); } runMigrators = new Content(SYSTEM_MIGRATION_CONTENT_ITEM, b.build()); } else { for (PropertyMigrator pm : migratorDependencySequence) { runMigrators.setProperty(pm.getName(), ts + ";" + i); } } session.getContentManager().update(runMigrators); }
/** * Writes commentCount of content * * @param node * @param session * @param write * @throws RepositoryException * @throws JSONException */ public static void writeCommentCountProperty( Content content, org.sakaiproject.nakamura.api.lite.Session session, JSONWriter writer, Repository repository) throws StorageClientException, JSONException { int commentCount = 0; String COMMENTCOUNT = "commentCount"; if (content.hasProperty(COMMENTCOUNT)) { commentCount = (Integer) content.getProperty(COMMENTCOUNT); } else { // no commentCount property on Content, then evaluate count and add property Content comments = null; org.sakaiproject.nakamura.api.lite.Session adminSession = null; try { comments = session.getContentManager().get(content.getPath() + "/comments"); if (comments != null) { commentCount = Iterables.size(comments.listChildPaths()); } content.setProperty(COMMENTCOUNT, commentCount); // save property adminSession = repository.loginAdministrative(); ContentManager adminContentManager = adminSession.getContentManager(); adminContentManager.update(content); } catch (org.sakaiproject.nakamura.api.lite.accesscontrol.AccessDeniedException e) { log.error(e.getMessage(), e); } finally { if (adminSession != null) { try { adminSession.logout(); } catch (Exception e) { log.error("Could not logout administrative session."); } } } } writer.key(COMMENTCOUNT); writer.value(commentCount); }
/** * {@inheritDoc} This post processor is only interested in posts to messages, so it should iterate * rapidly through all messages. * * @see * org.apache.sling.servlets.post.SlingPostProcessor#process(org.apache.sling.api.SlingHttpServletRequest, * java.util.List) */ public void process(SlingHttpServletRequest request, List<Modification> changes) throws Exception { Resource resource = request.getResource(); ResourceResolver resourceResolver = request.getResourceResolver(); if (SparseContentResource.SPARSE_CONTENT_RT.equals(resource.getResourceSuperType())) { Session session = resource.adaptTo(Session.class); ContentManager contentManager = session.getContentManager(); Map<Content, String> messageMap = new HashMap<Content, String>(); for (Modification m : changes) { try { switch (m.getType()) { case CREATE: case MODIFY: String path = m.getSource(); if (path.lastIndexOf("@") > 0) { path = path.substring(0, path.lastIndexOf("@")); } if (path.endsWith("/" + MessageConstants.PROP_SAKAI_MESSAGEBOX)) { path = path.substring( 0, path.length() - MessageConstants.PROP_SAKAI_MESSAGEBOX.length() - 1); } // The Modification Source is the Resource path, and so we // need to translate that into a Content path. // TODO This is not a cheap operation. We might be better off // if we start including the Content path in our Modification objects. Resource modifiedResource = resourceResolver.getResource(path); if (modifiedResource == null) { return; } Content content = modifiedResource.adaptTo(Content.class); String contentPath = content.getPath(); if (contentManager.exists(contentPath)) { content = contentManager.get(contentPath); if (content.hasProperty(SLING_RESOURCE_TYPE_PROPERTY) && content.hasProperty(PROP_SAKAI_MESSAGEBOX)) { if (SAKAI_MESSAGE_RT.equals(content.getProperty(SLING_RESOURCE_TYPE_PROPERTY)) && BOX_OUTBOX.equals(content.getProperty(PROP_SAKAI_MESSAGEBOX))) { String sendstate; if (content.hasProperty(PROP_SAKAI_SENDSTATE)) { sendstate = (String) content.getProperty(PROP_SAKAI_SENDSTATE); } else { sendstate = STATE_NONE; } messageMap.put(content, sendstate); } } } break; } } catch (StorageClientException ex) { LOGGER.warn("Failed to process on create for {} ", m.getSource(), ex); } catch (AccessDeniedException ex) { LOGGER.warn("Failed to process on create for {} ", m.getSource(), ex); } } List<String> handledNodes = new ArrayList<String>(); // Check if we have any nodes that have a pending state and launch an OSGi // event for (Entry<Content, String> mm : messageMap.entrySet()) { Content content = mm.getKey(); String path = content.getPath(); String state = mm.getValue(); if (!handledNodes.contains(path)) { if (STATE_NONE.equals(state) || STATE_PENDING.equals(state)) { content.setProperty(PROP_SAKAI_SENDSTATE, STATE_NOTIFIED); contentManager.update(content); Dictionary<String, Object> messageDict = new Hashtable<String, Object>(); // WARNING // We can't pass in the node, because the session might expire before the event gets // handled // This does mean that the listener will have to get the node each time, and probably // create a new session for each message // This might be heavy on performance. messageDict.put(EVENT_LOCATION, path); messageDict.put(UserConstants.EVENT_PROP_USERID, request.getRemoteUser()); LOGGER.debug("Launched event for message: {} ", path); Event pendingMessageEvent = new Event(PENDINGMESSAGE_EVENT, messageDict); // KERN-790: Initiate a synchronous event. try { eventAdmin.postEvent(pendingMessageEvent); handledNodes.add(path); } catch (Exception e) { LOGGER.warn("Failed to post message dispatch event, cause {} ", e.getMessage(), e); } } } } } }
private void setError(Content node, String error) { node.setProperty(MessageConstants.PROP_SAKAI_MESSAGEERROR, error); }
@SuppressWarnings("unchecked") public void onMessage(Message message) { try { LOGGER.debug("Started handling email jms message."); String nodePath = message.getStringProperty(NODE_PATH_PROPERTY); String contentPath = message.getStringProperty(CONTENT_PATH_PROPERTY); Object objRcpt = message.getObjectProperty(RECIPIENTS); List<String> recipients = null; if (objRcpt instanceof List<?>) { recipients = (List<String>) objRcpt; } else if (objRcpt instanceof String) { recipients = new LinkedList<String>(); String[] rcpts = StringUtils.split((String) objRcpt, ','); for (String rcpt : rcpts) { recipients.add(rcpt); } } if (contentPath != null && contentPath.length() > 0) { javax.jcr.Session adminSession = repository.loginAdministrative(null); org.sakaiproject.nakamura.api.lite.Session sparseSession = StorageClientUtils.adaptToSession(adminSession); try { ContentManager contentManager = sparseSession.getContentManager(); Content messageContent = contentManager.get(contentPath); if (objRcpt != null) { // validate the message if (messageContent != null) { if (messageContent.hasProperty(MessageConstants.PROP_SAKAI_MESSAGEBOX) && (MessageConstants.BOX_OUTBOX.equals( messageContent.getProperty(MessageConstants.PROP_SAKAI_MESSAGEBOX)) || MessageConstants.BOX_PENDING.equals( messageContent.getProperty(MessageConstants.PROP_SAKAI_MESSAGEBOX)))) { if (messageContent.hasProperty(MessageConstants.PROP_SAKAI_MESSAGEERROR)) { // We're retrying this message, so clear the errors messageContent.setProperty( MessageConstants.PROP_SAKAI_MESSAGEERROR, (String) null); } if (messageContent.hasProperty(MessageConstants.PROP_SAKAI_TO) && messageContent.hasProperty(MessageConstants.PROP_SAKAI_FROM)) { // make a commons-email message from the message MultiPartEmail email = null; try { email = constructMessage(messageContent, recipients, adminSession, sparseSession); email.setSmtpPort(smtpPort); email.setHostName(smtpServer); email.send(); } catch (EmailException e) { String exMessage = e.getMessage(); Throwable cause = e.getCause(); setError(messageContent, exMessage); LOGGER.warn("Unable to send email: " + exMessage); // Get the SMTP error code // There has to be a better way to do this boolean rescheduled = false; if (cause != null && cause.getMessage() != null) { String smtpError = cause.getMessage().trim(); try { int errorCode = Integer.parseInt(smtpError.substring(0, 3)); // All retry-able SMTP errors should have codes starting // with 4 scheduleRetry(errorCode, messageContent); rescheduled = true; } catch (NumberFormatException nfe) { // smtpError didn't start with an error code, let's dig for // it String searchFor = "response:"; int rindex = smtpError.indexOf(searchFor); if (rindex > -1 && (rindex + searchFor.length()) < smtpError.length()) { int errorCode = Integer.parseInt( smtpError.substring(searchFor.length(), searchFor.length() + 3)); scheduleRetry(errorCode, messageContent); rescheduled = true; } } } if (rescheduled) { LOGGER.info("Email {} rescheduled for redelivery. ", nodePath); } else { LOGGER.error("Unable to reschedule email for delivery: " + e.getMessage(), e); } } } else { setError(messageContent, "Message must have a to and from set"); } } else { setError(messageContent, "Not an outbox"); } if (!messageContent.hasProperty(MessageConstants.PROP_SAKAI_MESSAGEERROR)) { messageContent.setProperty( MessageConstants.PROP_SAKAI_MESSAGEBOX, MessageConstants.BOX_SENT); } } } else { String retval = "null"; setError( messageContent, "Expected recipients to be String or List<String>. Found " + retval); } } finally { if (adminSession != null) { adminSession.logout(); } } } } catch (PathNotFoundException e) { LOGGER.error(e.getMessage(), e); } catch (RepositoryException e) { LOGGER.error(e.getMessage(), e); } catch (JMSException e) { LOGGER.error(e.getMessage(), e); } catch (EmailDeliveryException e) { LOGGER.error(e.getMessage()); } catch (ClientPoolException e) { LOGGER.error(e.getMessage(), e); } catch (StorageClientException e) { LOGGER.error(e.getMessage(), e); } catch (AccessDeniedException e) { LOGGER.error(e.getMessage(), e); } }
public void createActivity( Session session, Content targetLocation, String userId, ActivityServiceCallback callback) throws AccessDeniedException, StorageClientException, ServletException, IOException { if (userId == null) { userId = session.getUserId(); } if (!userId.equals(session.getUserId()) && !User.ADMIN_USER.equals(session.getUserId())) { throw new IllegalStateException( "Only Administrative sessions may act on behalf of another user for activities"); } ContentManager contentManager = session.getContentManager(); // create activityStore if it does not exist String path = StorageClientUtils.newPath(targetLocation.getPath(), ACTIVITY_STORE_NAME); if (!contentManager.exists(path)) { contentManager.update( new Content( path, ImmutableMap.<String, Object>of( SLING_RESOURCE_TYPE_PROPERTY, ACTIVITY_STORE_RESOURCE_TYPE))); // inherit ACL from the target node, but let logged-in users write activities session .getAccessControlManager() .setAcl( Security.ZONE_CONTENT, path, new AclModification[] { new AclModification( AclModification.grantKey(Group.EVERYONE), Permissions.CAN_WRITE.getPermission(), Operation.OP_AND) }); } // create activity within activityStore String activityPath = StorageClientUtils.newPath(path, ActivityUtils.createId()); String activityFeedPath = StorageClientUtils.newPath(targetLocation.getPath(), "activityFeed"); if (!contentManager.exists(activityFeedPath)) { contentManager.update(new Content(activityFeedPath, null)); } if (!contentManager.exists(activityPath)) { contentManager.update( new Content( activityPath, ImmutableMap.of( JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY, (Object) ActivityConstants.ACTIVITY_ITEM_RESOURCE_TYPE))); } Content activtyNode = contentManager.get(activityPath); callback.processRequest(activtyNode); activtyNode = contentManager.get(activityPath); activtyNode.setProperty(PARAM_ACTOR_ID, userId); activtyNode.setProperty(ActivityConstants.PARAM_SOURCE, targetLocation.getPath()); Session adminSession = repository.loginAdministrative(); List<String> routesStr = new LinkedList<String>(); List<String> readers = new LinkedList<String>(); try { List<ActivityRoute> routes = activityRouterManager.getActivityRoutes(activtyNode, adminSession); if (routes != null) { for (ActivityRoute route : routes) { routesStr.add(route.getDestination()); if (route.getReaders() != null && route.getReaders().length > 0) { readers.addAll(Arrays.asList(route.getReaders())); } } } // store the routes as child content of the activity so we may lock it down to admin. It's // common for // the activity to be stored within the context of the content to which it pertains (e.g., // within the // pooled content item on which the user performed the activity), therefore we could expose // user // activity routes there -- that is an exposure of potentially sensitive content such as who // the user's // connections are. String routesPath = StorageClientUtils.newPath(activtyNode.getPath(), ActivityConstants.PARAM_ROUTES); contentManager.update( new Content( routesPath, ImmutableMap.<String, Object>of( ActivityConstants.PARAM_ROUTES, routesStr.toArray(new String[routesStr.size()])))); adminSession .getAccessControlManager() .setAcl( Security.ZONE_CONTENT, routesPath, new AclModification[] { new AclModification( AclModification.denyKey(User.ANON_USER), Permissions.ALL.getPermission(), Operation.OP_REPLACE), new AclModification( AclModification.denyKey(Group.EVERYONE), Permissions.ALL.getPermission(), Operation.OP_REPLACE), new AclModification( AclModification.denyKey(userId), Permissions.ALL.getPermission(), Operation.OP_REPLACE) }); if (!readers.isEmpty()) { AclModification[] readerAcls = new AclModification[readers.size()]; int i = 0; for (String reader : readers) { // ensure all the necessary readers/routes can read the activity readerAcls[i] = new AclModification( AclModification.grantKey(reader), Permissions.CAN_READ.getPermission(), Operation.OP_OR); i++; } adminSession .getAccessControlManager() .setAcl(Security.ZONE_CONTENT, activtyNode.getPath(), readerAcls); } } finally { SparseUtils.logoutQuietly(adminSession); } // store the activity node contentManager.update(activtyNode); // post the asynchronous OSGi event final Dictionary<String, String> properties = new Hashtable<String, String>(); properties.put(UserConstants.EVENT_PROP_USERID, userId); properties.put(ActivityConstants.EVENT_PROP_PATH, activityPath); properties.put("path", activityPath); properties.put("resourceType", ActivityConstants.ACTIVITY_ITEM_RESOURCE_TYPE); EventUtils.sendOsgiEvent(properties, LITE_EVENT_TOPIC, eventAdmin); }
/** * {@inheritDoc} * * @see * org.sakaiproject.nakamura.connections.StatePair#transition(org.sakaiproject.nakamura.api.lite.content.Content, * org.sakaiproject.nakamura.api.lite.content.Content) */ public void transition(Content thisNode, Content otherNode) { thisNode.setProperty(SAKAI_CONNECTION_STATE, thisState.toString()); otherNode.setProperty(SAKAI_CONNECTION_STATE, otherState.toString()); }
public void internalImportContent( ContentManager contentManager, JSONObject json, String path, boolean replaceProperties, AccessControlManager accessControlManager) throws JSONException, StorageClientException, AccessDeniedException { Iterator<String> keys = json.keys(); Map<String, Object> properties = new HashMap<String, Object>(); List<AclModification> modifications = Lists.newArrayList(); while (keys.hasNext()) { String key = keys.next(); if (!key.startsWith("jcr:")) { Object obj = json.get(key); String pathKey = getPathElement(key); Class<?> typeHint = getElementType(key); if (obj instanceof JSONObject) { if (key.endsWith("@grant")) { JSONObject acl = (JSONObject) obj; int bitmap = getPermissionBitMap(acl.getJSONArray("permission")); Operation op = getOperation(acl.getString("operation")); modifications.add(new AclModification(AclModification.grantKey(pathKey), bitmap, op)); } else if (key.endsWith("@deny")) { JSONObject acl = (JSONObject) obj; int bitmap = getPermissionBitMap(acl.getJSONArray("permission")); Operation op = getOperation(acl.getString("operation")); modifications.add(new AclModification(AclModification.denyKey(pathKey), bitmap, op)); } else if (key.endsWith("@Delete")) { StorageClientUtils.deleteTree(contentManager, path); } else { // need to do somethingwith delete here internalImportContent( contentManager, (JSONObject) obj, path + "/" + pathKey, replaceProperties, accessControlManager); } } else if (obj instanceof JSONArray) { if (key.endsWith("@Delete")) { properties.put(pathKey, new RemoveProperty()); } else { // This represents a multivalued property JSONArray arr = (JSONArray) obj; properties.put(pathKey, getArray(arr, typeHint)); } } else { if (key.endsWith("@Delete")) { properties.put(pathKey, new RemoveProperty()); } else { properties.put(pathKey, getObject(obj, typeHint)); } } } } Content content = contentManager.get(path); if (content == null) { contentManager.update(new Content(path, properties)); LOGGER.info("Created Node {} {}", path, properties); } else { for (Entry<String, Object> e : properties.entrySet()) { if (replaceProperties || !content.hasProperty(e.getKey())) { LOGGER.info("Updated Node {} {} {} ", new Object[] {path, e.getKey(), e.getValue()}); content.setProperty(e.getKey(), e.getValue()); } } contentManager.update(content); } if (modifications.size() > 0) { accessControlManager.setAcl( Security.ZONE_CONTENT, path, modifications.toArray(new AclModification[modifications.size()])); } }