public static void writeFileNode( Content content, org.sakaiproject.nakamura.api.lite.Session session, JSONWriter write, int maxDepth, boolean objectInProgress) throws JSONException, StorageClientException { if (content == null) { log.warn("Can't output null content."); return; } if (!objectInProgress) { write.object(); } // dump all the properties. ExtendedJSONWriter.writeContentTreeToWriter(write, content, true, maxDepth); // The permissions for this session. writePermissions(content, session, write); write.key(JcrConstants.JCR_LASTMODIFIED); Calendar cal = new GregorianCalendar(); cal.setTimeInMillis(StorageClientUtils.toLong(content.getProperty(Content.LASTMODIFIED_FIELD))); write.value(DateUtils.iso8601(cal)); write.key(JcrConstants.JCR_MIMETYPE); write.value(content.getProperty(Content.MIMETYPE_FIELD)); write.key(JcrConstants.JCR_DATA); write.value(StorageClientUtils.toLong(content.getProperty(Content.LENGTH_FIELD))); if (!objectInProgress) { write.endObject(); } }
public static void writeLinkNode( Content content, org.sakaiproject.nakamura.api.lite.Session session, JSONWriter writer, boolean objectInProgress) throws StorageClientException, JSONException { if (!objectInProgress) { writer.object(); } ContentManager contentManager = session.getContentManager(); // Write all the properties. ExtendedJSONWriter.writeNodeContentsToWriter(writer, content); // permissions writePermissions(content, session, writer); // Write the actual file. if (content.hasProperty(SAKAI_LINK)) { String linkPath = (String) content.getProperty(SAKAI_LINK); writer.key("file"); try { Content fileNode = contentManager.get(linkPath); writeFileNode(fileNode, session, writer); } catch (org.sakaiproject.nakamura.api.lite.accesscontrol.AccessDeniedException e) { writer.value(false); } } if (!objectInProgress) { writer.endObject(); } }
/** * {@inheritDoc} * * @see * org.sakaiproject.nakamura.api.solr.IndexingHandler#getDocuments(org.sakaiproject.nakamura.api.solr.RepositorySession, * org.osgi.service.event.Event) */ @Override public Collection<SolrInputDocument> getDocuments(RepositorySession repoSession, Event event) { LOGGER.debug("getDocuments for {}", event); String path = (String) event.getProperty(IndexingHandler.FIELD_PATH); List<SolrInputDocument> documents = Lists.newArrayList(); if (!StringUtils.isBlank(path)) { Session session = repoSession.adaptTo(Session.class); try { ContentManager cm = session.getContentManager(); Content content = cm.get(path); SolrInputDocument doc = new SolrInputDocument(); for (Entry<String, String> prop : PROPERTIES.entrySet()) { String key = prop.getKey(); Object value = content.getProperty(key); if (value != null) { doc.addField(PROPERTIES.get(key), value); } } doc.setField(_DOC_SOURCE_OBJECT, content); documents.add(doc); } catch (StorageClientException e) { LOGGER.error(e.getMessage(), e); } catch (AccessDeniedException e) { LOGGER.error(e.getMessage(), e); } } return documents; }
/** * {@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); } } } }
/** * {@inheritDoc} * * @see * org.sakaiproject.nakamura.api.solr.IndexingHandler#getDocuments(org.sakaiproject.nakamura.api.solr.RepositorySession, * org.osgi.service.event.Event) */ public Collection<SolrInputDocument> getDocuments( RepositorySession repositorySession, Event event) { String path = (String) event.getProperty(FIELD_PATH); logger.info("Indexing connections at path {}", path); List<SolrInputDocument> documents = Lists.newArrayList(); if (!StringUtils.isBlank(path)) { try { Session session = repositorySession.adaptTo(Session.class); ContentManager cm = session.getContentManager(); Content content = cm.get(path); int lastSlash = path.lastIndexOf('/'); String contactName = path.substring(lastSlash + 1); AuthorizableManager am = session.getAuthorizableManager(); Authorizable contactAuth = am.findAuthorizable(contactName); if (content != null && contactAuth != null) { SolrInputDocument doc = new SolrInputDocument(); for (Entry<String, String> prop : WHITELISTED_PROPS.entrySet()) { String key = prop.getKey(); Object value = content.getProperty(key); if (value != null) { doc.addField(WHITELISTED_PROPS.get(key), value); } } // flatten out the contact so we can search it Map<String, Object> contactProps = contactAuth.getSafeProperties(); if (contactAuth != null) { for (String prop : FLATTENED_PROPS) { Object value = contactProps.get(prop); if (value != null) { doc.addField(prop, value); } } } doc.addField(_DOC_SOURCE_OBJECT, content); documents.add(doc); } else { logger.warn( "Did not index {}: Content == {}; Contact Auth == {}", new Object[] {path, content, contactAuth}); } } catch (StorageClientException e) { logger.error(e.getMessage(), e); } catch (AccessDeniedException e) { logger.error(e.getMessage(), e); } } logger.debug("Got documents {} ", documents); return documents; }
private void addDefaultFields(SolrInputDocument doc, RepositorySession repositorySession) throws StorageClientException { Object o = doc.getFieldValue(_DOC_SOURCE_OBJECT); if (o instanceof Content) { Content content = (Content) o; boolean writeReaders = true; Object suppressReadersValue = doc.getFieldValue(FIELD_SUPPRESS_READERS); if (suppressReadersValue instanceof String) { if (FIELD_SUPPRESS_READERS.equals(suppressReadersValue)) { writeReaders = false; doc.removeField(FIELD_SUPPRESS_READERS); } } if (writeReaders) { String[] principals = getReadingPrincipals(repositorySession, Security.ZONE_CONTENT, content.getPath()); for (String principal : principals) { doc.addField(FIELD_READERS, principal); } } else { doc.removeField(FIELD_READERS); } if (content.hasProperty(SLING_RESOURCE_TYPE)) { doc.setField(FIELD_RESOURCE_TYPE, content.getProperty(SLING_RESOURCE_TYPE)); } String path = content.getPath(); // we don't overwrite the id field if it has been provided if (!doc.getFieldNames().contains(FIELD_ID)) { doc.setField(FIELD_ID, path); } while (path != null) { doc.addField(FIELD_PATH, path); String newPath = Utils.getParentPath(path); if (path.equals(newPath)) { break; } path = newPath; } doc.removeField(_DOC_SOURCE_OBJECT); } else { TelemetryCounter.incrementValue("solr", "SparseIndexingServiceImpl", "docMissingSource"); LOGGER.error( "Note to Developer: Indexer must add the _source fields so that the default fields can be set, please correct, SolrDoc was {} ", doc); throw new StorageClientException( _DOC_SOURCE_OBJECT + " fields was missing from Solr Document, please correct the handler implementation"); } }
@SuppressWarnings("unchecked") private <T> T getHandler( RepositorySession repositorySession, String path, Map<String, T> indexers, Map<String, String> ignoreCache) { org.sakaiproject.nakamura.api.lite.Session sparseSession = repositorySession.adaptTo(org.sakaiproject.nakamura.api.lite.Session.class); while (path != null) { if (!ignoreCache.containsKey(path)) { try { if (sparseSession != null) { ContentManager contentManager = sparseSession.getContentManager(); Content c = contentManager.get(path); LOGGER.debug("Checking Content at {} got {} ", path, c); if (c != null) { if (c.hasProperty("sling:resourceType")) { String resourceType = (String) c.getProperty("sling:resourceType"); T handler = indexers.get(resourceType); if (handler != null) { LOGGER.debug( "Handler of type {} found {} for {} from {} ", new Object[] {resourceType, handler, path, indexers}); return handler; } else { LOGGER.debug("Ignoring {}; no handler", path); synchronized (this) { ignoreCache.put(path, path); } } } else { LOGGER.debug("Ignored {} no resource type ", path); } } } } catch (StorageClientException e) { LOGGER.debug(e.getMessage(), e); } catch (AccessDeniedException e) { LOGGER.debug(e.getMessage(), e); } } if (StorageClientUtils.isRoot(path)) { break; } path = Utils.getParentPath(path); } return (T) defaultHandler; }
/** * Give a JSON representation of the content. * * @param content * @param session * @param write The {@link JSONWriter} to output to. * @param depth * @throws JSONException * @throws StorageClientException */ protected void handleContent( final Content content, final Session session, final JSONWriter write, final int depth) throws JSONException, StorageClientException { write.object(); final String type = (String) content.getProperty(SLING_RESOURCE_TYPE_PROPERTY); if (FilesConstants.RT_SAKAI_LINK.equals(type)) { FileUtils.writeLinkNode(content, session, write, true); } else { FileUtils.writeFileNode(content, session, write, depth, true); } FileUtils.writeComments(content, session, write); FileUtils.writeCommentCountProperty(content, session, write, repository); write.endObject(); }
/* * getPageTree: returns List of all pages under the passed path */ private List<Content> getPageTree(Content pageContent) { List<Content> contentList = new ArrayList(); // Add to list only if content is a page String resourceType = (String) pageContent.getProperty("sling:resourceType"); if (resourceType != null && resourceType.equals("sakai/page")) { contentList.add(pageContent); } if (pageContent != null) { for (Content page : pageContent.listChildren()) { contentList.addAll(getPageTree(page)); } } return contentList; }
private IndexingHandler getHandler(RepositorySession repositorySession, String path) { org.sakaiproject.nakamura.api.lite.Session sparseSession = repositorySession.adaptTo(org.sakaiproject.nakamura.api.lite.Session.class); while (path != null) { if (!ignoreCache.containsKey(path)) { try { if (sparseSession != null) { ContentManager contentManager = sparseSession.getContentManager(); Content c = contentManager.get(path); LOGGER.debug("Checking Content at {} got {} ", path, c); if (c != null) { if (c.hasProperty(SLING_RESOURCE_TYPE)) { String resourceType = (String) c.getProperty(SLING_RESOURCE_TYPE); IndexingHandler handler = indexers.get(resourceType); if (handler != null) { LOGGER.debug( "Handler of type {} found {} for {} from {} ", new Object[] {resourceType, handler, path, indexers}); return handler; } else { TelemetryCounter.incrementValue( "solr", "SparseIndexingServiceImpl-ignoredPath", path); LOGGER.debug("Ignored {} no handler for {} ", path, resourceType); ignoreCache.put(path, path); } } else { LOGGER.debug("Ignored {} no resource type ", path); } } } } catch (StorageClientException e) { LOGGER.debug(e.getMessage(), e); } catch (AccessDeniedException e) { LOGGER.debug(e.getMessage(), e); } } if (StorageClientUtils.isRoot(path)) { break; } path = Utils.getParentPath(path); } TelemetryCounter.incrementValue("solr", "SparseIndexingServiceImpl", "useDefaultHandler"); return defaultHandler; }
private void scheduleRetry(int errorCode, Content contentNode) { // All retry-able SMTP errors should have codes starting with 4 if ((errorCode / 100) == 4) { long retryCount = 0; if (contentNode.hasProperty(MessageConstants.PROP_SAKAI_RETRY_COUNT)) { retryCount = StorageClientUtils.toLong( contentNode.getProperty(MessageConstants.PROP_SAKAI_RETRY_COUNT)); } if (retryCount < maxRetries) { Job job = new Job() { public void execute(JobContext jc) { Map<String, Serializable> config = jc.getConfiguration(); Properties eventProps = new Properties(); eventProps.put(NODE_PATH_PROPERTY, config.get(NODE_PATH_PROPERTY)); Event retryEvent = new Event(QUEUE_NAME, eventProps); eventAdmin.postEvent(retryEvent); } }; HashMap<String, Serializable> jobConfig = new HashMap<String, Serializable>(); jobConfig.put(NODE_PATH_PROPERTY, contentNode.getPath()); int retryIntervalMillis = retryInterval * 60000; Date nextTry = new Date(System.currentTimeMillis() + (retryIntervalMillis)); try { scheduler.fireJobAt(null, job, jobConfig, nextTry); } catch (Exception e) { LOGGER.error(e.getMessage(), e); } } else { setError(contentNode, "Unable to send message, exhausted SMTP retries."); } } else { LOGGER.warn("Not scheduling a retry for error code not of the form 4xx."); } }
@Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { Resource resource = request.getResource(); Node node = resource.adaptTo(Node.class); Content content = resource.adaptTo(Content.class); System.err.println("Node is " + node + " content is " + content); String link = null; try { if (node != null && node.hasProperty(FilesConstants.SAKAI_LINK)) { link = node.getProperty(FilesConstants.SAKAI_LINK).getString(); } else if (content != null && content.hasProperty(FilesConstants.SAKAI_LINK)) { link = (String) content.getProperty(FilesConstants.SAKAI_LINK); } System.err.println("Link is " + link); if (link != null) { String[] linkProps = StringUtils.split(link, ':'); LinkHandler handler = null; String path = null; if (linkProps.length == 2) { handler = fileHandlerTracker.getProcessorByName(linkProps[0]); path = linkProps[1]; } else { if (node != null) { handler = new JcrInternalFileHandler(); } else { handler = new SparseContentInternalFileHandler(); } path = link; } if (handler != null) { handler.handleFile(request, response, path); } } } catch (RepositoryException e) { LOGGER.warn(e.getMessage(), e); response.sendError(500, "Unable to handle linked file."); } }
private void writeCanManageProperty( SlingHttpServletRequest request, JSONWriter write, Session session, Content contentResult) throws StorageClientException, JSONException, AccessDeniedException { write.key("sakai:canmanage"); Authorizable thisUser = session.getAuthorizableManager().findAuthorizable(request.getRemoteUser()); Collection<String> principals = new ArrayList<String>(); principals.addAll(Arrays.asList(thisUser.getPrincipals())); principals.add(request.getRemoteUser()); boolean canManage = false; for (String principal : principals) { if (Arrays.asList( StorageClientUtils.nonNullStringArray( (String[]) contentResult.getProperty("sakai:pooled-content-manager"))) .contains(principal)) { canManage = true; } } write.value(canManage); }
/** * 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); }
private void addDefaultFields(SolrInputDocument doc, RepositorySession repositorySession) throws StorageClientException { Object o = doc.getFieldValue(_DOC_SOURCE_OBJECT); if (o instanceof Content) { Content content = (Content) o; String[] principals = getReadingPrincipals(repositorySession, Security.ZONE_CONTENT, content.getPath()); for (String principal : principals) { doc.addField(FIELD_READERS, principal); } if (content.hasProperty("sling:resourceType")) { doc.setField(FIELD_RESOURCE_TYPE, content.getProperty("sling:resourceType")); } String path = content.getPath(); // we don't overwrite the id field if it has been provided if (!doc.getFieldNames().contains(FIELD_ID)) { doc.setField(FIELD_ID, path); } while (path != null) { doc.addField(FIELD_PATH, path); String newPath = Utils.getParentPath(path); if (path.equals(newPath)) { break; } path = newPath; } doc.removeField(_DOC_SOURCE_OBJECT); } else { LOGGER.error( "Note to Developer: Indexer must add the _source fields so that the default fields can be set, please correct, SolrDoc was {} ", doc); throw new StorageClientException( _DOC_SOURCE_OBJECT + " fields was missing from Solr Document, please correct the handler implementation"); } }
/** * {@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 MultiPartEmail constructMessage( Content contentNode, List<String> recipients, javax.jcr.Session session, org.sakaiproject.nakamura.api.lite.Session sparseSession) throws EmailDeliveryException, StorageClientException, AccessDeniedException, PathNotFoundException, RepositoryException { MultiPartEmail email = new MultiPartEmail(); // TODO: the SAKAI_TO may make no sense in an email context // and there does not appear to be any distinction between Bcc and To in java mail. Set<String> toRecipients = new HashSet<String>(); Set<String> bccRecipients = new HashSet<String>(); for (String r : recipients) { bccRecipients.add(convertToEmail(r.trim(), sparseSession)); } if (contentNode.hasProperty(MessageConstants.PROP_SAKAI_TO)) { String[] tor = StringUtils.split((String) contentNode.getProperty(MessageConstants.PROP_SAKAI_TO), ','); for (String r : tor) { r = convertToEmail(r.trim(), sparseSession); if (bccRecipients.contains(r)) { toRecipients.add(r); bccRecipients.remove(r); } } } for (String r : toRecipients) { try { email.addTo(convertToEmail(r, sparseSession)); } catch (EmailException e) { throw new EmailDeliveryException( "Invalid To Address [" + r + "], message is being dropped :" + e.getMessage(), e); } } for (String r : bccRecipients) { try { email.addBcc(convertToEmail(r, sparseSession)); } catch (EmailException e) { throw new EmailDeliveryException( "Invalid Bcc Address [" + r + "], message is being dropped :" + e.getMessage(), e); } } if (contentNode.hasProperty(MessageConstants.PROP_SAKAI_FROM)) { String from = (String) contentNode.getProperty(MessageConstants.PROP_SAKAI_FROM); try { email.setFrom(convertToEmail(from, sparseSession)); } catch (EmailException e) { throw new EmailDeliveryException( "Invalid From Address [" + from + "], message is being dropped :" + e.getMessage(), e); } } else { throw new EmailDeliveryException("Must provide a 'from' address."); } if (contentNode.hasProperty(MessageConstants.PROP_SAKAI_BODY)) { String messageBody = (String) contentNode.getProperty(MessageConstants.PROP_SAKAI_BODY); // if this message has a template, use it LOGGER.debug( "Checking for sakai:templatePath and sakai:templateParams properties on the outgoing message's node."); if (contentNode.hasProperty(MessageConstants.PROP_TEMPLATE_PATH) && contentNode.hasProperty(MessageConstants.PROP_TEMPLATE_PARAMS)) { Map<String, String> parameters = getTemplateProperties( (String) contentNode.getProperty(MessageConstants.PROP_TEMPLATE_PARAMS)); String templatePath = (String) contentNode.getProperty(MessageConstants.PROP_TEMPLATE_PATH); LOGGER.debug("Got the path '{0}' to the template for this outgoing message.", templatePath); Node templateNode = session.getNode(templatePath); if (templateNode.hasProperty("sakai:template")) { String template = templateNode.getProperty("sakai:template").getString(); LOGGER.debug("Pulled the template body from the template node: {0}", template); messageBody = templateService.evaluateTemplate(parameters, template); LOGGER.debug("Performed parameter substitution in the template: {0}", messageBody); } } else { LOGGER.debug( "Message node '{0}' does not have sakai:templatePath and sakai:templateParams properties", contentNode.getPath()); } try { email.setMsg(messageBody); } catch (EmailException e) { throw new EmailDeliveryException( "Invalid Message Body, message is being dropped :" + e.getMessage(), e); } } if (contentNode.hasProperty(MessageConstants.PROP_SAKAI_SUBJECT)) { email.setSubject((String) contentNode.getProperty(MessageConstants.PROP_SAKAI_SUBJECT)); } ContentManager contentManager = sparseSession.getContentManager(); for (String streamId : contentNode.listStreams()) { String description = null; if (contentNode.hasProperty( StorageClientUtils.getAltField( MessageConstants.PROP_SAKAI_ATTACHMENT_DESCRIPTION, streamId))) { description = (String) contentNode.getProperty( StorageClientUtils.getAltField( MessageConstants.PROP_SAKAI_ATTACHMENT_DESCRIPTION, streamId)); } LiteEmailDataSource ds = new LiteEmailDataSource(contentManager, contentNode, streamId); try { email.attach(ds, streamId, description); } catch (EmailException e) { throw new EmailDeliveryException( "Invalid Attachment [" + streamId + "] message is being dropped :" + e.getMessage(), e); } } return email; }
@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); } }
/** * {@inheritDoc} * * @see * org.apache.sling.api.servlets.SlingSafeMethodsServlet#doGet(org.apache.sling.api.SlingHttpServletRequest, * org.apache.sling.api.SlingHttpServletResponse) */ @Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException { try { List<Content> contentList = null; RequestParameter rp = request.getRequestParameter("path"); ResourceResolver resourceResolver = request.getResourceResolver(); if (rp != null) { String contentPath = rp.getString("UTF-8"); if (contentPath.startsWith("/_groupa:")) { contentPath = contentPath.replaceFirst("/_groupa:", "/~"); } if (contentPath.endsWith("/")) { contentPath = contentPath.substring(0, contentPath.length() - 1); } Resource pagesResource = resourceResolver.getResource(contentPath); if (pagesResource != null) { contentList = getPageTree(pagesResource.adaptTo(Content.class)); ; } } response.setContentType("application/json"); response.setCharacterEncoding("UTF-8"); PrintWriter w = response.getWriter(); ExtendedJSONWriter writer = new ExtendedJSONWriter(w); writer.object(); // pages info int messageCount = 0; writer.key("items"); writer.value(255); writer.key("results"); writer.array(); if (contentList != null) { for (int i = 0; i < contentList.size(); i++) { Content page = contentList.get(i); writer.object(); writer.key("jcr:path"); writer.value( page.getPath() .replaceFirst( LitePersonalUtils.PATH_AUTHORIZABLE, LitePersonalUtils.PATH_RESOURCE_AUTHORIZABLE)); for (String messagePropKey : page.getProperties().keySet()) { writer.key(messagePropKey); writer.value(massageValue(messagePropKey, page.getProperty(messagePropKey))); } writer.endObject(); messageCount++; } } writer.endArray(); writer.key("total"); writer.value(messageCount); writer.endObject(); } catch (JSONException e) { LOG.error("Failed to create proper JSON response in /var/search/page", e); response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to create proper JSON response."); } }
/** * {@inheritDoc} * * @see * org.sakaiproject.nakamura.api.search.solr.SolrSearchBatchResultProcessor#writeResults(org.apache.sling.api.SlingHttpServletRequest, * org.apache.sling.commons.json.io.JSONWriter, java.util.Iterator) */ public void writeResults( SlingHttpServletRequest request, JSONWriter writer, Iterator<Result> iterator) throws JSONException { try { Session session = StorageClientUtils.adaptToSession( request.getResourceResolver().adaptTo(javax.jcr.Session.class)); ContentManager cm = session.getContentManager(); List<String> basePosts = new ArrayList<String>(); Map<String, List<Post>> postChildren = new HashMap<String, List<Post>>(); Map<String, Post> allPosts = new HashMap<String, Post>(); while (iterator.hasNext()) { Result result = iterator.next(); Content content = cm.get(result.getPath()); if (content == null) { continue; } Post p = new Post(content, session); allPosts.put((String) content.getProperty(MessageConstants.PROP_SAKAI_ID), p); if (content.hasProperty(DiscussionConstants.PROP_REPLY_ON)) { // This post is a reply on another post. String replyon = (String) content.getProperty(DiscussionConstants.PROP_REPLY_ON); if (!postChildren.containsKey(replyon)) { postChildren.put(replyon, new ArrayList<Post>()); } postChildren.get(replyon).add(p); } else { // This post is not a reply to another post, thus it is a basepost. basePosts.add(p.getPostId()); } } // Now that we have all the base posts, we can sort the replies properly for (Entry<String, List<Post>> postChild : postChildren.entrySet()) { Post parentPost = allPosts.get(postChild.getKey()); if (parentPost != null) { List<Post> childrenList = parentPost.getChildren(); List<Post> childrenActual = postChild.getValue(); childrenList.addAll(childrenActual); } } // The posts are sorted, now return them as json. for (String basePostId : basePosts) { allPosts .get(basePostId) .outputPostAsJSON( (ExtendedJSONWriter) writer, presenceService, basicUserInfoService, session); } } catch (StorageClientException e) { throw new RuntimeException(e.getMessage(), e); } catch (AccessDeniedException e) { throw new RuntimeException(e.getMessage(), e); } catch (RepositoryException e) { throw new RuntimeException(e.getMessage(), e); } }