diff --git a/config/alfresco/templates/webscripts/org/alfresco/repository/events/raiseevent.get.desc.xml b/config/alfresco/templates/webscripts/org/alfresco/repository/events/raiseevent.get.desc.xml
new file mode 100644
index 0000000000..cde3cb67a0
--- /dev/null
+++ b/config/alfresco/templates/webscripts/org/alfresco/repository/events/raiseevent.get.desc.xml
@@ -0,0 +1,10 @@
+
+ alfresco-browser-event
+ Raises an alfresco browser event, e.g /api/events/mysite/documentdetails/view
+ /api/events/{siteId}/{component}/{action}
+ /api/events/{component}/{action}
+ argument
+ user
+ required
+ internal
+
diff --git a/config/alfresco/web-scripts-application-context.xml b/config/alfresco/web-scripts-application-context.xml
index fd9fe71055..1dde0bc7bf 100644
--- a/config/alfresco/web-scripts-application-context.xml
+++ b/config/alfresco/web-scripts-application-context.xml
@@ -1581,6 +1581,12 @@
+
+
+
+
+
diff --git a/source/java/org/alfresco/repo/web/scripts/events/RaiseBrowserEventGet.java b/source/java/org/alfresco/repo/web/scripts/events/RaiseBrowserEventGet.java
new file mode 100644
index 0000000000..c1ebe85be2
--- /dev/null
+++ b/source/java/org/alfresco/repo/web/scripts/events/RaiseBrowserEventGet.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2005-2014 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.repo.web.scripts.events;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.alfresco.repo.events.EventPublisher;
+import org.alfresco.repo.security.permissions.AccessDeniedException;
+import org.alfresco.service.cmr.site.SiteInfo;
+import org.alfresco.service.cmr.site.SiteService;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONTokener;
+import org.springframework.extensions.webscripts.AbstractWebScript;
+import org.springframework.extensions.webscripts.Status;
+import org.springframework.extensions.webscripts.WebScriptException;
+import org.springframework.extensions.webscripts.WebScriptRequest;
+import org.springframework.extensions.webscripts.WebScriptResponse;
+import org.springframework.util.StringUtils;
+
+/**
+* Raises an alfresco browser event, e.g /api/events/mysite/documentdetails/view
+*
+* @author Gethin James
+* @since 5.0
+ */
+public class RaiseBrowserEventGet extends AbstractWebScript
+{
+ private EventPublisher eventPublisher;
+ private SiteService siteService;
+
+ public void setEventPublisher(EventPublisher eventPublisher)
+ {
+ this.eventPublisher = eventPublisher;
+ }
+ public void setSiteService(SiteService siteService)
+ {
+ this.siteService = siteService;
+ }
+
+ @Override
+ public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException
+ {
+ Map templateVars = req.getServiceMatch().getTemplateVars();
+ SiteInfo siteInfo = null;
+ String component = null;
+ String action = null;
+
+ if (templateVars != null)
+ {
+ if (templateVars.containsKey("siteId"))
+ {
+ //Validates the site id
+ siteInfo = siteService.getSite(templateVars.get("siteId"));
+ if (siteInfo == null)
+ {
+ throw new AccessDeniedException("No such site: " + templateVars.get("siteId"));
+ }
+
+ }
+ component = templateVars.get("component");
+ action = templateVars.get("action");
+ }
+
+ String attributes = req.getParameter("attributes");
+ if (attributes != null)
+ {
+ if (!validJsonMap(attributes))
+ {
+ throw new WebScriptException(Status.STATUS_BAD_REQUEST, "Invalid JSON Object: " + attributes);
+ }
+ }
+
+ if (StringUtils.hasText(component) && StringUtils.hasText(action))
+ {
+ eventPublisher.publishBrowserEvent(req, siteInfo==null?null:siteInfo.getShortName(), component, action, attributes);
+ }
+
+ res.setStatus(Status.STATUS_OK);
+ }
+
+ /**
+ * Validate Json to ensure its a Map.
+ * @param attributes jsonmap
+ * @return boolean true if valid
+ */
+ private boolean validJsonMap(String attributes)
+ {
+ try
+ {
+ @SuppressWarnings("unused")
+ JSONObject json = new JSONObject(new JSONTokener(attributes));
+ return true;
+ }
+ catch (JSONException error)
+ {
+ return false;
+ }
+
+ }
+
+}
diff --git a/source/test-java/org/alfresco/repo/web/scripts/events/RaiseEventTest.java b/source/test-java/org/alfresco/repo/web/scripts/events/RaiseEventTest.java
new file mode 100644
index 0000000000..ebb8a42f36
--- /dev/null
+++ b/source/test-java/org/alfresco/repo/web/scripts/events/RaiseEventTest.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2005-2014 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.repo.web.scripts.events;
+
+import java.util.List;
+
+import org.alfresco.events.types.BrowserEvent;
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.events.EventPublisherForTestingOnly;
+import org.alfresco.repo.security.authentication.AuthenticationComponent;
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.alfresco.repo.site.SiteModel;
+import org.alfresco.repo.web.scripts.BaseWebScriptTest;
+import org.alfresco.service.cmr.security.MutableAuthenticationService;
+import org.alfresco.service.cmr.security.PersonService;
+import org.alfresco.service.cmr.site.SiteInfo;
+import org.alfresco.service.cmr.site.SiteService;
+import org.alfresco.service.cmr.site.SiteVisibility;
+import org.alfresco.util.PropertyMap;
+import org.springframework.extensions.webscripts.Status;
+import org.springframework.extensions.webscripts.TestWebScriptServer.GetRequest;
+
+/**
+ * Tests the {@link RaiseBrowserEventGet} endpoint
+ */
+public class RaiseEventTest extends BaseWebScriptTest
+{
+
+ private static final String USER_ONE = "RaiseEventTestuser1";
+ private static final String SITE_EVENTS_TEST = "RaiseEventTestSite";
+ private static final String GET_URL = "/api/events/";
+
+ private EventPublisherForTestingOnly eventPublisher;
+ private AuthenticationComponent authenticationComponent;
+ private SiteService siteService;
+ private MutableAuthenticationService authenticationService;
+ private PersonService personService;
+
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ this.authenticationComponent = (AuthenticationComponent)getServer().getApplicationContext().getBean("authenticationComponent");
+ this.siteService = (SiteService)getServer().getApplicationContext().getBean("SiteService");
+ this.eventPublisher = (EventPublisherForTestingOnly)getServer().getApplicationContext().getBean("eventPublisher");
+ this.authenticationService = (MutableAuthenticationService)getServer().getApplicationContext().getBean("AuthenticationService");
+ this.personService = (PersonService)getServer().getApplicationContext().getBean("PersonService");
+ this.authenticationComponent.setCurrentUser(AuthenticationUtil.getAdminUserName());
+
+ // Create test site
+ // - only create the site if it doesn't already exist
+ SiteInfo siteInfo = this.siteService.getSite(SITE_EVENTS_TEST);
+ if (siteInfo == null)
+ {
+ this.siteService.createSite("RaiseEventSitePreset", SITE_EVENTS_TEST, SITE_EVENTS_TEST+" Title", "SiteDescription", SiteVisibility.PRIVATE);
+ }
+
+ createUser(USER_ONE, SiteModel.SITE_COLLABORATOR);
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ // admin user required to delete user
+ this.authenticationComponent.setCurrentUser(AuthenticationUtil.getAdminUserName());
+
+ SiteInfo siteInfo = this.siteService.getSite(SITE_EVENTS_TEST);
+ if (siteInfo != null)
+ {
+ // delete invite site
+ siteService.deleteSite(SITE_EVENTS_TEST);
+ }
+
+ // delete the users
+ deleteUser(USER_ONE);
+ }
+
+ /**
+ * Tests GET requests to create browser events.
+ *
+ * @throws Exception
+ */
+ public void testRaiseEvent() throws Exception
+ {
+ sendRequest(new GetRequest(GET_URL+"mypage/edit"), Status.STATUS_OK);
+ sendRequest(new GetRequest(GET_URL), Status.STATUS_NOT_FOUND);
+ sendRequest(new GetRequest(GET_URL+"mypage"), Status.STATUS_NOT_FOUND);
+ sendRequest(new GetRequest(GET_URL+SITE_EVENTS_TEST+"/sitepage/view"), Status.STATUS_OK);
+ sendRequest(new GetRequest(GET_URL+SITE_EVENTS_TEST+"/sitepage/view?attributes=xyz"), Status.STATUS_BAD_REQUEST);
+ sendRequest(new GetRequest(GET_URL+SITE_EVENTS_TEST+"/specialpage/view?attributes={\"source\": \"bob\", \"target\": \"hope\"}"), Status.STATUS_OK);
+
+ List browserEvents = eventPublisher.getQueueByType(BrowserEvent.class);
+ int found = 0;
+ for (BrowserEvent be : browserEvents)
+ {
+ if ("mypage".equals(be.getComponent()))
+ {
+ found ++;
+ assertEquals("edit", be.getAction());
+ continue;
+ }
+
+ if ("sitepage".equals(be.getComponent()))
+ {
+ found ++;
+ assertEquals(SITE_EVENTS_TEST, be.getSiteId());
+ assertEquals("view", be.getAction());
+ continue;
+ }
+
+ if ("specialpage".equals(be.getComponent()))
+ {
+ found ++;
+ assertEquals(SITE_EVENTS_TEST, be.getSiteId());
+ assertEquals("view", be.getAction());
+ assertEquals("{\"source\": \"bob\", \"target\": \"hope\"}", be.getAttributes());
+ continue;
+ }
+ }
+ assertEquals(3, found); //Found and validated 3 events.
+
+ }
+
+ private void createUser(String userName, String role)
+ {
+ // if user with given user name doesn't already exist then create user
+ if (this.authenticationService.authenticationExists(userName) == false)
+ {
+ // create user
+ this.authenticationService.createAuthentication(userName, "password".toCharArray());
+
+ // create person properties
+ PropertyMap personProps = new PropertyMap();
+ personProps.put(ContentModel.PROP_USERNAME, userName);
+ personProps.put(ContentModel.PROP_FIRSTNAME, "FirstName123");
+ personProps.put(ContentModel.PROP_LASTNAME, "LastName123");
+ personProps.put(ContentModel.PROP_EMAIL, "FirstName123.LastName123@email.com");
+ personProps.put(ContentModel.PROP_JOBTITLE, "JobTitle123");
+ personProps.put(ContentModel.PROP_JOBTITLE, "Organisation123");
+
+ // create person node for user
+ this.personService.createPerson(personProps);
+ }
+
+ // add the user as a member with the given role
+ this.siteService.setMembership(SITE_EVENTS_TEST, userName, role);
+ }
+ private void deleteUser(String userName)
+ {
+ personService.deletePerson(userName);
+ if (this.authenticationService.authenticationExists(userName))
+ {
+ this.authenticationService.deleteAuthentication(userName);
+ }
+ }
+
+}