@Override
  @TransactionAttribute(TransactionAttributeType.REQUIRED)
  public void deleteThreadMessage(String path) throws ForumServiceException {
    logIt("deleteThreadMessage(...) called");
    logger.debug("params : path=" + path);

    try {
      // Security check
      String caller = membership.getProfilePathForConnectedIdentifier();
      if (caller == null) {
        throw new ForumServiceException("Could not get connected profile");
      }
      logIt("caller: " + caller);
      pep.checkSecurity(caller, path, "delete");
      // Look up given path and check resource type
      FactoryResourceIdentifier identifier = binding.lookup(path);
      checkResourceType(identifier, ThreadMessage.RESOURCE_NAME);
      // Find the entity
      ThreadMessage msg = em.find(ThreadMessage.class, identifier.getId());
      if (msg == null) {
        throw new ForumServiceException("unable to find a msg for id " + identifier.getId());
      }
      if (!browser.hasChildren(path)) {
        HashMap<String, String> values = forumWS.deleteThreadMessage(msg.getId());
        if (values != null && !values.isEmpty()) {
          String code = (String) values.get("statusCode");
          String msgTxt = (String) values.get("statusMessage");
          logIt("Message Code:" + code + " Message: " + msgTxt);
          if (!code.equals(CollaborationUtils.SUCCESS_CODE)) {
            throw new ForumServiceException(
                "Error code recieved from the WS." + " Code" + code + " Message:" + msgTxt);
          }
          em.remove(msg);
          // Delete the policy and unbind the resource from this path
          String policyId = binding.getProperty(path, FactoryResourceProperty.POLICY_ID, false);
          pap.deletePolicy(policyId);
          binding.unbind(path);
          // notify
          notification.throwEvent(
              new Event(
                  path,
                  caller,
                  ThreadMessage.RESOURCE_NAME,
                  Event.buildEventType(
                      ForumService.SERVICE_NAME, ThreadMessage.RESOURCE_NAME, "delete"),
                  ""));
        } else {
          throw new ForumServiceException("No valid answer from the WS.Check logs.");
        }
      } else {
        throw new ForumServiceException("Thread message has children and cannot be deleted.");
      }
    } catch (Exception e) {
      // ctx.setRollbackOnly();
      logger.error("Unable to delete the message at path " + path, e);
      throw new ForumServiceException("Unable to delete the message at path " + path, e);
    }
  }
 @Override
 @TransactionAttribute(TransactionAttributeType.SUPPORTS)
 public ThreadMessage readThreadMessage(String path) throws ForumServiceException {
   logIt("readThreadMessage(...) called");
   logger.debug("params : path=" + path);
   ThreadMessage msg = null;
   try {
     // Security check
     String caller = membership.getProfilePathForConnectedIdentifier();
     if (caller == null) {
       throw new ForumServiceException("Could not get connected profile");
     }
     logIt("caller: " + caller);
     pep.checkSecurity(caller, path, "read");
     // Look up given path and check resource type
     FactoryResourceIdentifier identifier = binding.lookup(path);
     checkResourceType(identifier, ThreadMessage.RESOURCE_NAME);
     // sFind the entity
     msg = em.find(ThreadMessage.class, identifier.getId());
     if (msg == null) {
       throw new ForumServiceException("Unable to find a message for id " + identifier.getId());
     }
     // Call the WS to retrieve values that are not stored in
     // factory
     HashMap<String, Object> values = forumWS.readThreadMessage(msg.getForumId(), msg.getId());
     if (values != null && !values.isEmpty()) {
       String code = (String) values.get("statusCode");
       String msgTxt = (String) values.get("statusMessage");
       logIt("Message Code:" + code + " Message: " + msgTxt);
       if (!code.equals(CollaborationUtils.SUCCESS_CODE) || values.get("ThreadMessage") == null) {
         throw new ForumServiceException(
             "Error code recieved from the WS." + " Code" + code + " Message:" + msgTxt);
       }
       // FIXME The path is missing in the replies list....Use Browser
       // method
       MessageDTO msgWS = (MessageDTO) values.get("ThreadMessage");
       if (msgWS != null) {
         // We don't persist the following
         // (messageBody,datePosted,numReplies,messageReplies)
         // so we retrieve values from WS
         msg.setMessageBody(msgWS.getMessageBody());
         msg.setDatePosted(msgWS.getDatePosted());
         msg.setNumReplies(msgWS.getNumReplies());
         if (msgWS.getMessageReplies() != null) {
           msg.setMessageReplies(convertHashMap(path, msgWS.getMessageReplies()));
         }
         // notify
         notification.throwEvent(
             new Event(
                 path,
                 caller,
                 ThreadMessage.RESOURCE_NAME,
                 Event.buildEventType(
                     ForumService.SERVICE_NAME, ThreadMessage.RESOURCE_NAME, "read"),
                 ""));
         logIt(msg.toString());
       } else {
         throw new ForumServiceException("Error in WS response.");
       }
     } else {
       throw new ForumServiceException("Error in recieving extra details from WS.");
     }
     return msg;
   } catch (Exception e) {
     logger.error("unable to read the message at path " + path, e);
     throw new ForumServiceException("unable to read the message at path " + path, e);
   }
 }
  @Override
  public String createMessage(String path, ThreadMessage message, String isReply)
      throws ForumServiceException {

    logIt("createThreadMessage(...) called");
    logger.debug("params : path=" + path + " isReply: " + message);
    String newMsgId = null;
    try {
      // check supplied values
      checkThreadValues(
          message.getName(),
          message.getForumId(),
          message.getMessageBody(),
          message.getDatePosted());
      // Security check
      String caller = membership.getProfilePathForConnectedIdentifier();
      if (caller == null) {
        throw new ForumServiceException("Could not get connected profile");
      }
      logIt("caller: " + caller);
      String parentPath = PathHelper.getParentPath(path);
      pep.checkSecurity(caller, parentPath, "create");
      //
      String parentId = "";
      boolean isReplyBoolean = Boolean.valueOf(isReply);
      logIt("Is Reply: " + isReplyBoolean);
      if (isReplyBoolean) {
        try {
          // Check if parent is thread
          ThreadMessage parentMsg = readThreadMessage(parentPath);
          parentId = parentMsg.getId();
          logIt("Succefully read parent thread. Id: " + parentId);
        } catch (Exception e) {
          throw new ForumServiceException(
              "Path is not valid for replying to a thread.Please check " + path);
        }
      }
      // Call Mermig WS
      HashMap<String, String> values =
          forumWS.createThreadMessage(
              message.getForumId(),
              parentId,
              message.getName(),
              message.getMessageBody(),
              isReplyBoolean);
      //
      if (values != null && !values.isEmpty()) {
        String code = (String) values.get("statusCode");
        String msg = (String) values.get("statusMessage");
        logIt("Message Code:" + code + " Message: " + msg);
        if (!code.equals(CollaborationUtils.SUCCESS_CODE)) {
          throw new ForumServiceException(
              "Error code recieved from the WS." + " Code" + code + " Message:" + msg);
        }
        // We persist only id,path,name,parentId,forumId and author
        String newId = (String) values.get("messageId");
        ThreadMessage tm = new ThreadMessage();
        tm.setId(newId);
        tm.setResourcePath(path);
        tm.setName(message.getName());
        tm.setParentId(parentId);
        tm.setForumId(message.getForumId());
        // FIXME we need author not profile path.
        tm.setAuthor(caller);
        em.persist(tm);
        // Bind the entity with the path and the identifier
        logIt("Bind the " + tm.getFactoryResourceIdentifier() + " to " + path);
        binding.bind(tm.getFactoryResourceIdentifier(), path);
        binding.setProperty(
            path, FactoryResourceProperty.CREATION_TIMESTAMP, "" + System.currentTimeMillis());
        binding.setProperty(
            path, FactoryResourceProperty.LAST_UPDATE_TIMESTAMP, "" + System.currentTimeMillis());
        binding.setProperty(path, FactoryResourceProperty.AUTHOR, caller);
        // Create policy (owner)
        String policyId = UUID.randomUUID().toString();
        pap.createPolicy(policyId, PAPServiceHelper.buildOwnerPolicy(policyId, caller, path));
        binding.setProperty(path, FactoryResourceProperty.OWNER, caller);
        binding.setProperty(path, FactoryResourceProperty.POLICY_ID, policyId);
        // notify
        notification.throwEvent(
            new Event(
                path,
                caller,
                ThreadMessage.RESOURCE_NAME,
                Event.buildEventType(
                    ForumService.SERVICE_NAME, ThreadMessage.RESOURCE_NAME, "create"),
                ""));
        //
        newMsgId = tm.getId();
        logIt(tm.toString());
      } else {
        throw new ForumServiceException("No valid answer from the WS.Check logs.");
      }
      return newMsgId;
    } catch (Exception e) {
      // ctx.setRollbackOnly();
      logger.error("Unable to create the thread message at path " + path, e);
      throw new ForumServiceException("Unable to create the thread message at path " + path, e);
    }
  }