From f6b2827434493fe1c057feeb26032a0c674360e7 Mon Sep 17 00:00:00 2001 From: Brian Clements Date: Tue, 11 Feb 2014 16:06:03 -0600 Subject: [PATCH] Issue #2756 new collaboration openfire plugin and http service new servlet http service that communicates with openfire for configuration new openfire plugin to reflect new http service openfire and http service no longer need to be on same machine moved http header parsing code from ogc to common util updated collaboration http code to prefer XML instead of HTML Former-commit-id: ff23569984eee43927c10ca041ca7e0ca4d40a3b --- ...XmppMessage.java => IHttpXmppMessage.java} | 10 +- .../session/PeerToPeerCommHelper.java | 50 +- .../CollaborationDrawingResource.java | 1 + .../CollaborationObjectEventStorage.java | 217 +++++++-- .../raytheon/uf/common/comm/HttpClient.java | 26 +- .../com.raytheon.uf.common.http/.classpath | 7 + edexOsgi/com.raytheon.uf.common.http/.project | 28 ++ .../.settings/org.eclipse.jdt.core.prefs | 7 + .../META-INF/MANIFEST.MF | 9 + .../build.properties | 4 + .../uf}/common/http/AcceptHeaderParser.java | 5 +- .../uf}/common/http/AcceptHeaderValue.java | 3 +- .../raytheon/uf}/common/http/MimeType.java | 31 +- .../feature.xml | 7 + .../META-INF/MANIFEST.MF | 3 +- .../uf/edex/ogc/common/OgcResponse.java | 2 +- .../uf/edex/ogc/common/feature/GmlUtils.java | 2 +- .../common/feature/JsonFeatureFormatter.java | 2 +- .../common/feature/ShpFeatureFormatter.java | 2 +- .../feature/SimpleFeatureFormatter.java | 2 +- .../edex/ogc/common/http/OgcHttpHandler.java | 3 + .../META-INF/MANIFEST.MF | 3 +- .../wfs/provider/AbstractWfsProvider.java | 2 +- .../uf/edex/wfs/request/GetFeatureReq.java | 2 +- .../uf/edex/wfs/request/WfsRequest.java | 2 +- .../uf/edex/wfs/v1_1_0/Capabilities.java | 2 +- .../uf/edex/wfs/v1_1_0/Wfs1_1_0Provider.java | 2 +- .../uf/edex/wfs/v2_0_0/Capabilities.java | 2 +- .../uf/edex/wfs/v2_0_0/Wfs2_0_0Provider.java | 2 +- .../collaboration.dataserver/.classpath | 7 + .../collaboration.dataserver/.project | 28 ++ .../.settings/org.eclipse.jdt.core.prefs | 7 + .../META-INF/MANIFEST.MF | 10 + .../collaboration.dataserver/build.properties | 4 + .../config/credentials.properties | 2 + .../config/settings.properties | 5 + .../collaboration/dataserver/Config.java | 273 +++++++++++ .../collaboration/dataserver/DataService.java | 236 ++++++++++ .../dataserver/DataserverMain.java | 129 +++++ .../collaboration/dataserver/FileManager.java | 443 ++++++++++++++++++ .../dataserver/RestException.java} | 53 +-- .../dataserver/WebServerRunner.java | 93 ++++ .../dataserver/XmppServerConnection.java | 135 ++++++ .../collaboration.dataserver/start.sh | 12 + .../collaboration.dataserver/stop.sh | 10 + .../META-INF/MANIFEST.MF | 3 +- .../HttpConfigurationPlugin.java | 259 ++++++++++ ...HttpdCollaborationConfigurationPlugin.java | 278 ----------- .../configuration/ConfigurationPacket.java | 42 +- .../HttpdCollaborationConfiguration.java | 83 ---- .../configuration/PacketPreferences.java | 91 ++++ ...HttpdCollaborationNotRunningException.java | 73 --- .../HttpdCollaborationStatusException.java | 74 --- .../collaboration/http/HttpStatusMonitor.java | 259 ++++++++++ .../httpd/HttpdCollaborationConfReader.java | 65 --- ...dCollaborationPropertiesConfiguration.java | 84 ---- .../HttpdCollaborationStatusMonitor.java | 180 ------- .../iq/AbstractConfigHandler.java | 301 ++++++++++++ .../collaboration/iq/DataAuthHandler.java | 184 ++++++++ .../collaboration/iq/HttpAddressHandler.java | 177 +++++++ ...=> CollaborationSessionEventListener.java} | 49 +- .../plugin.xml | 14 +- .../setup.xml | 2 +- ...p => http-collaboration-monitor-admin.jsp} | 76 ++- 64 files changed, 3138 insertions(+), 1041 deletions(-) rename cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/identity/event/{IHttpdXmppMessage.java => IHttpXmppMessage.java} (85%) create mode 100644 edexOsgi/com.raytheon.uf.common.http/.classpath create mode 100644 edexOsgi/com.raytheon.uf.common.http/.project create mode 100644 edexOsgi/com.raytheon.uf.common.http/.settings/org.eclipse.jdt.core.prefs create mode 100644 edexOsgi/com.raytheon.uf.common.http/META-INF/MANIFEST.MF create mode 100644 edexOsgi/com.raytheon.uf.common.http/build.properties rename edexOsgi/{com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc => com.raytheon.uf.common.http/src/com/raytheon/uf}/common/http/AcceptHeaderParser.java (93%) rename edexOsgi/{com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc => com.raytheon.uf.common.http/src/com/raytheon/uf}/common/http/AcceptHeaderValue.java (94%) rename edexOsgi/{com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc => com.raytheon.uf.common.http/src/com/raytheon/uf}/common/http/MimeType.java (89%) create mode 100644 javaUtilities/collaboration.dataserver/.classpath create mode 100644 javaUtilities/collaboration.dataserver/.project create mode 100644 javaUtilities/collaboration.dataserver/.settings/org.eclipse.jdt.core.prefs create mode 100644 javaUtilities/collaboration.dataserver/META-INF/MANIFEST.MF create mode 100644 javaUtilities/collaboration.dataserver/build.properties create mode 100644 javaUtilities/collaboration.dataserver/config/credentials.properties create mode 100644 javaUtilities/collaboration.dataserver/config/settings.properties create mode 100644 javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/Config.java create mode 100644 javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/DataService.java create mode 100644 javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/DataserverMain.java create mode 100644 javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/FileManager.java rename javaUtilities/{com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/util/HttpdCollaborationUtil.java => collaboration.dataserver/src/com/raytheon/collaboration/dataserver/RestException.java} (53%) create mode 100644 javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/WebServerRunner.java create mode 100644 javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/XmppServerConnection.java create mode 100755 javaUtilities/collaboration.dataserver/start.sh create mode 100755 javaUtilities/collaboration.dataserver/stop.sh create mode 100644 javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/HttpConfigurationPlugin.java delete mode 100644 javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/HttpdCollaborationConfigurationPlugin.java delete mode 100644 javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/configuration/HttpdCollaborationConfiguration.java create mode 100644 javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/configuration/PacketPreferences.java delete mode 100644 javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/exception/HttpdCollaborationNotRunningException.java delete mode 100644 javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/exception/HttpdCollaborationStatusException.java create mode 100644 javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/http/HttpStatusMonitor.java delete mode 100644 javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/httpd/HttpdCollaborationConfReader.java delete mode 100644 javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/httpd/HttpdCollaborationPropertiesConfiguration.java delete mode 100644 javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/httpd/HttpdCollaborationStatusMonitor.java create mode 100644 javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/iq/AbstractConfigHandler.java create mode 100644 javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/iq/DataAuthHandler.java create mode 100644 javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/iq/HttpAddressHandler.java rename javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/listener/{HttpdCollaborationSessionEventListener.java => CollaborationSessionEventListener.java} (69%) rename javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/web/{httpd-collaboration-monitor-admin.jsp => http-collaboration-monitor-admin.jsp} (60%) diff --git a/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/identity/event/IHttpdXmppMessage.java b/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/identity/event/IHttpXmppMessage.java similarity index 85% rename from cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/identity/event/IHttpdXmppMessage.java rename to cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/identity/event/IHttpXmppMessage.java index 6e8b5b1dc0..73aa76554a 100644 --- a/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/identity/event/IHttpdXmppMessage.java +++ b/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/identity/event/IHttpXmppMessage.java @@ -23,7 +23,7 @@ import java.util.regex.Pattern; /** * Used to store constants that are used to validate, analyze, and parse status - * and configuration messages associated with the AWIPS II httpd collaboration + * and configuration messages associated with the AWIPS II http collaboration * server. * *
@@ -34,6 +34,8 @@ import java.util.regex.Pattern;
  * ------------ ---------- ----------- --------------------------
  * Aug 7, 2012            bkowal     Initial creation
  * Dec 18, 2013 2562       bclement     removed preamble from patterns
+ * Feb 17, 2014 2756       bclement     removed URL regex that was too specific
+ *                                      renamed to remove httpd reference
  * 
  * 
* @@ -41,7 +43,7 @@ import java.util.regex.Pattern; * @version 1.0 */ -public interface IHttpdXmppMessage { +public interface IHttpXmppMessage { // Constant Strings public static final String URL_PARAMETER_NAME = "sessionDataHttpURL"; @@ -49,8 +51,6 @@ public interface IHttpdXmppMessage { static final String SUFFIX_REGEX = " : .+"; - static final String COLLABORATION_URL_REGEX = "http://.+:[1-9][0-9]*/session_data/"; - // Regex Patterns public static final Pattern configErrorPattern = Pattern .compile(ERROR_PARAMETER_NAME + SUFFIX_REGEX); @@ -58,6 +58,4 @@ public interface IHttpdXmppMessage { public static final Pattern configURLPattern = Pattern .compile(URL_PARAMETER_NAME + SUFFIX_REGEX); - public static final Pattern urlPattern = Pattern - .compile(COLLABORATION_URL_REGEX); } diff --git a/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/session/PeerToPeerCommHelper.java b/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/session/PeerToPeerCommHelper.java index fe22817887..4ebba1f156 100644 --- a/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/session/PeerToPeerCommHelper.java +++ b/cave/com.raytheon.uf.viz.collaboration.comm/src/com/raytheon/uf/viz/collaboration/comm/provider/session/PeerToPeerCommHelper.java @@ -19,6 +19,9 @@ **/ package com.raytheon.uf.viz.collaboration.comm.provider.session; +import java.net.URI; +import java.net.URL; + import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Packet; @@ -27,9 +30,10 @@ import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.viz.collaboration.comm.Activator; +import com.raytheon.uf.viz.collaboration.comm.identity.CollaborationException; import com.raytheon.uf.viz.collaboration.comm.identity.ISession; +import com.raytheon.uf.viz.collaboration.comm.identity.event.IHttpXmppMessage; import com.raytheon.uf.viz.collaboration.comm.identity.event.IHttpdCollaborationConfigurationEvent; -import com.raytheon.uf.viz.collaboration.comm.identity.event.IHttpdXmppMessage; import com.raytheon.uf.viz.collaboration.comm.identity.event.ITextMessageEvent; import com.raytheon.uf.viz.collaboration.comm.identity.user.IUser; import com.raytheon.uf.viz.collaboration.comm.provider.SessionPayload; @@ -38,6 +42,7 @@ import com.raytheon.uf.viz.collaboration.comm.provider.Tools; import com.raytheon.uf.viz.collaboration.comm.provider.event.ChatMessageEvent; import com.raytheon.uf.viz.collaboration.comm.provider.event.HttpdCollaborationConfigurationEvent; import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter; +import com.raytheon.uf.viz.collaboration.comm.provider.user.UserId; /** * Listens for peer to peer messages and routes them appropriately. @@ -54,6 +59,8 @@ import com.raytheon.uf.viz.collaboration.comm.provider.user.IDConverter; * data now in packet extension * Dec 19, 2013 2563 bclement removed wait for HTTP config, added reset * Feb 13, 2014 2751 bclement changed IQualifiedID objects to IUser + * Feb 17, 2014 2756 bclement null check for message from field + * moved url validation from regex to java utility * * * @@ -67,7 +74,7 @@ public class PeerToPeerCommHelper implements PacketListener { .getHandler(PeerToPeerCommHelper.class); private static volatile String httpServer; - + /** * Get HTTP server address. This value will be updated if the server sends * new HTTP configuration. If this address is null, the server most likely @@ -101,7 +108,14 @@ public class PeerToPeerCommHelper implements PacketListener { public void processPacket(Packet packet) { if (packet instanceof Message) { Message msg = (Message) packet; - if (IDConverter.isFromRoom(msg.getFrom())) { + String fromStr = msg.getFrom(); + if (fromStr == null) { + // from server + UserId account = CollaborationConnection.getConnection() + .getUser(); + fromStr = account.getHost(); + } + if (IDConverter.isFromRoom(fromStr)) { // venues will have their own listeners return; } @@ -204,11 +218,11 @@ public class PeerToPeerCommHelper implements PacketListener { */ private void handleConfiguration(String body) { // Determine if an error has occurred. - if (IHttpdXmppMessage.configErrorPattern.matcher(body).matches()) { + if (IHttpXmppMessage.configErrorPattern.matcher(body).matches()) { statusHandler.handle( UFStatus.Priority.ERROR, this.getCollaborationConfigurationParameterValue(body, - IHttpdXmppMessage.ERROR_PARAMETER_NAME) + IHttpXmppMessage.ERROR_PARAMETER_NAME) + ". Shared Display Sessions have been disabled."); this.disableSharedDisplaySession(); // terminate execution @@ -216,7 +230,7 @@ public class PeerToPeerCommHelper implements PacketListener { } // Validate the configuration. - if (IHttpdXmppMessage.configURLPattern.matcher(body).matches() == false) { + if (IHttpXmppMessage.configURLPattern.matcher(body).matches() == false) { statusHandler .handle(UFStatus.Priority.PROBLEM, "Received invalid configuration from openfire. Shared Display Sessions have been disabled."); @@ -225,24 +239,32 @@ public class PeerToPeerCommHelper implements PacketListener { } // Remove the parameter name. - String httpdCollaborationURL = this + String httpCollaborationURL = this .getCollaborationConfigurationParameterValue(body, - IHttpdXmppMessage.URL_PARAMETER_NAME); + IHttpXmppMessage.URL_PARAMETER_NAME); // validate the url. - if (IHttpdXmppMessage.urlPattern.matcher(httpdCollaborationURL) - .matches() == false) { + try { + URL u = new URL(httpCollaborationURL); + URI uri = u.toURI(); + if (!uri.getScheme().equalsIgnoreCase("http")) { + throw new CollaborationException( + "Provided URL doesn't use the HTTP scheme"); + } + } catch (Exception e) { statusHandler.handle(UFStatus.Priority.PROBLEM, "Received an invalid http url from openfire - " - + httpdCollaborationURL - + ". Shared Display Sessions have been disabled."); + + httpCollaborationURL + + ". Shared Display Sessions have been disabled.", + e); this.disableSharedDisplaySession(); return; } - httpServer = httpdCollaborationURL; + + httpServer = httpCollaborationURL; // configuration is valid; publish it. IHttpdCollaborationConfigurationEvent configurationEvent = new HttpdCollaborationConfigurationEvent( - httpdCollaborationURL); + httpCollaborationURL); manager.postEvent(configurationEvent); } diff --git a/cave/com.raytheon.uf.viz.collaboration.display/src/com/raytheon/uf/viz/collaboration/display/rsc/telestrator/CollaborationDrawingResource.java b/cave/com.raytheon.uf.viz.collaboration.display/src/com/raytheon/uf/viz/collaboration/display/rsc/telestrator/CollaborationDrawingResource.java index 71f3c8d99a..ab7d0a6a6f 100644 --- a/cave/com.raytheon.uf.viz.collaboration.display/src/com/raytheon/uf/viz/collaboration/display/rsc/telestrator/CollaborationDrawingResource.java +++ b/cave/com.raytheon.uf.viz.collaboration.display/src/com/raytheon/uf/viz/collaboration/display/rsc/telestrator/CollaborationDrawingResource.java @@ -62,6 +62,7 @@ import com.vividsolutions.jts.geom.Coordinate; * ------------ ---------- ----------- -------------------------- * May 23, 2012 mschenke Initial creation * Jan 30, 2014 2698 bclement changed UserId to VenueParticipant + * Feb 13, 2014 2751 bclement VenueParticipant refactor * * * diff --git a/cave/com.raytheon.uf.viz.collaboration.display/src/com/raytheon/uf/viz/collaboration/display/storage/CollaborationObjectEventStorage.java b/cave/com.raytheon.uf.viz.collaboration.display/src/com/raytheon/uf/viz/collaboration/display/storage/CollaborationObjectEventStorage.java index a23710c7cd..e9310eb3b5 100644 --- a/cave/com.raytheon.uf.viz.collaboration.display/src/com/raytheon/uf/viz/collaboration/display/storage/CollaborationObjectEventStorage.java +++ b/cave/com.raytheon.uf.viz.collaboration.display/src/com/raytheon/uf/viz/collaboration/display/storage/CollaborationObjectEventStorage.java @@ -19,18 +19,25 @@ **/ package com.raytheon.uf.viz.collaboration.display.storage; +import java.io.ByteArrayInputStream; import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.message.BasicHeader; import com.raytheon.uf.common.comm.HttpClient; import com.raytheon.uf.common.comm.HttpClient.HttpClientResponse; @@ -49,7 +56,9 @@ import com.raytheon.uf.viz.remote.graphics.events.DisposeObjectEvent; import com.raytheon.uf.viz.remote.graphics.events.ICreationEvent; /** - * Class responsible for object event storage. Will persist/retrieve objects + * Class responsible for object event storage. Will persist/retrieve objects. + * When listing remote directories, this client uses the HTTP Accepts header to + * prefer XML format, but also accepts HTML. * *
  * 
@@ -58,6 +67,7 @@ import com.raytheon.uf.viz.remote.graphics.events.ICreationEvent;
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Apr 20, 2012            mschenke     Initial creation
+ * Feb 17, 2014 2756       bclement     added xml parsing for HTTP directory listing
  * 
  * 
* @@ -90,12 +100,20 @@ public class CollaborationObjectEventStorage implements return persistance; } + public static final String ACCEPTS_HEADER = "Accepts"; + + public static final String XML_CONTENT_TYPE = "text/xml"; + + public static final String HTML_CONTENT_TYPE = "text/html"; + private String sessionDataURL; private HttpClient client; private int displayId; + private final XMLInputFactory staxFactory = XMLInputFactory.newInstance(); + private CollaborationObjectEventStorage(ISharedDisplaySession session, int displayId) { this.displayId = displayId; @@ -116,6 +134,7 @@ public class CollaborationObjectEventStorage implements public IPersistedEvent persistEvent(AbstractDispatchingObjectEvent event) throws CollaborationException { if (event instanceof ICreationEvent) { + // TODO this is for pre 14.3 compatibility createFolder(String.valueOf(event.getObjectId())); } else if (event instanceof DisposeObjectEvent) { // Do not delete anything off the server, users may still be @@ -205,6 +224,13 @@ public class CollaborationObjectEventStorage implements } } + /** + * Execute get request for object stored at event's resource path + * + * @param event + * @return null if object was deleted + * @throws CollaborationException + */ private CollaborationHttpPersistedObject retreiveStoredObject( CollaborationHttpPersistedEvent event) throws CollaborationException { @@ -213,9 +239,10 @@ public class CollaborationObjectEventStorage implements HttpClientResponse response = executeRequest(get); if (isSuccess(response.code)) { try { - CollaborationHttpPersistedObject dataObject = (CollaborationHttpPersistedObject) SerializationUtil - .transformFromThrift(CompressionUtil - .uncompress(response.data)); + CollaborationHttpPersistedObject dataObject = SerializationUtil + .transformFromThrift( + CollaborationHttpPersistedObject.class, + CompressionUtil.uncompress(response.data)); if (dataObject != null) { dataObject.dataSize = response.data.length; } @@ -244,6 +271,8 @@ public class CollaborationObjectEventStorage implements throws CollaborationException { String objectPath = objectId + "/"; HttpGet get = new HttpGet(sessionDataURL + objectPath); + get.addHeader(new BasicHeader(ACCEPTS_HEADER, XML_CONTENT_TYPE + "," + + HTML_CONTENT_TYPE)); HttpClientResponse response = executeRequest(get); if (isSuccess(response.code) == false) { if (isNotExists(response.code)) { @@ -252,38 +281,21 @@ public class CollaborationObjectEventStorage implements throw new CollaborationException("Error retrieving object (" + objectId + ") events, received code: " + response.code); } - CollaborationHttpPersistedEvent event = new CollaborationHttpPersistedEvent(); - List objectEvents = new ArrayList(); // parse out links of objects - String htmlStr = new String(response.data); - int searchIdx = 0; - String searchStrStart = ""; - int searchStrLen = searchStrStart.length(); - while (searchIdx > -1) { - int previousIdx = searchIdx; - int foundAt = htmlStr.indexOf(searchStrStart, searchIdx); - // reset searchIdx to -1 until found - searchIdx = -1; - if (foundAt > previousIdx) { - foundAt += searchStrLen; - int endsAt = htmlStr.indexOf(searchStrEnd, foundAt); - if (endsAt > foundAt) { - String object = htmlStr.substring(foundAt, endsAt); - if (object.endsWith(objectEnding)) { - event.setResourcePath(objectPath + object); - CollaborationHttpPersistedObject eventObject = retreiveStoredObject(event); - if (eventObject != null) { - objectEvents.add(eventObject); - } else { - // Object was deleted, abort - return new AbstractDispatchingObjectEvent[0]; - } - } - searchIdx = endsAt + 1; - } + List objectEvents; + try { + if (response.contentType != null + && response.contentType.toLowerCase().contains("xml")) { + objectEvents = parseXmlResponseData(objectPath, response.data); + } else { + objectEvents = parseHtmlResponseData(objectPath, response.data); } + } catch (XMLStreamException e) { + throw new CollaborationException("Error parsing response data", e); + } + if (objectEvents == null) { + // Object was deleted, abort + return new AbstractDispatchingObjectEvent[0]; } // Sort by creation time @@ -306,10 +318,118 @@ public class CollaborationObjectEventStorage implements return events; } + /** + * Parse response from HTTP directory listing in xml format + * + * @param objectPath + * @param responseData + * @return null if object was deleted + * @throws XMLStreamException + * @throws CollaborationException + */ + private List parseXmlResponseData( + String objectPath, byte[] responseData) throws XMLStreamException, + CollaborationException { + + CollaborationHttpPersistedEvent event = new CollaborationHttpPersistedEvent(); + List objectEvents = new ArrayList(); + String text; + boolean inFileTag = false; + XMLStreamReader reader = staxFactory + .createXMLStreamReader(new ByteArrayInputStream(responseData)); + while (reader.hasNext()) { + int staxEvent = reader.next(); + switch (staxEvent) { + case XMLStreamConstants.START_ELEMENT: + String localName = reader.getLocalName(); + inFileTag = localName.equalsIgnoreCase("file"); + break; + case XMLStreamConstants.CHARACTERS: + text = reader.getText().trim(); + if (inFileTag && text.endsWith(".obj")) { + event.setResourcePath(objectPath + text); + CollaborationHttpPersistedObject eventObject = retreiveStoredObject(event); + if (eventObject != null) { + objectEvents.add(eventObject); + } else { + // Object was deleted, abort + return null; + } + } + } + } + return objectEvents; + } + + /** + * Parse httpd HTML directory listing response + * + * @param objectPath + * @param responseData + * @return null if object was deleted + * @throws XMLStreamException + * @throws CollaborationException + */ + private List parseHtmlResponseData( + String objectPath, byte[] responseData) throws XMLStreamException, + CollaborationException { + CollaborationHttpPersistedEvent event = new CollaborationHttpPersistedEvent(); + List objectEvents = new ArrayList(); + String htmlStr = new String(responseData); + int searchIdx = 0; + String searchStrStart = ""; + int searchStrLen = searchStrStart.length(); + while (searchIdx > -1) { + int previousIdx = searchIdx; + int foundAt = htmlStr.indexOf(searchStrStart, searchIdx); + // reset searchIdx to -1 until found + searchIdx = -1; + if (foundAt > previousIdx) { + foundAt += searchStrLen; + int endsAt = htmlStr.indexOf(searchStrEnd, foundAt); + if (endsAt > foundAt) { + String object = htmlStr.substring(foundAt, endsAt); + if (object.endsWith(objectEnding)) { + event.setResourcePath(objectPath + object); + CollaborationHttpPersistedObject eventObject = retreiveStoredObject(event); + if (eventObject != null) { + objectEvents.add(eventObject); + } else { + // Object was deleted, abort + return null; + } + } + searchIdx = endsAt + 1; + } + } + } + return objectEvents; + } + + /** + * Perform a MKCOL operation on httpd with DAV module. + * + * @deprecated MKCOL is only required for DAV (pre 14.3) + * + * @param folderPath + * @throws CollaborationException + */ + @Deprecated private void createFolder(String folderPath) throws CollaborationException { createFolder(URI.create(sessionDataURL + folderPath)); } + /** + * Perform a MKCOL operation on httpd with DAV module. + * + * @deprecated MKCOL is only required for DAV (pre 14.3) + * + * @param folderPath + * @throws CollaborationException + */ + @Deprecated private void createFolder(URI folderPath) throws CollaborationException { HttpRequestBase mkcol = new HttpRequestBase() { @Override @@ -325,6 +445,12 @@ public class CollaborationObjectEventStorage implements } } + /** + * Delete all files at and below uri + * + * @param uri + * @throws CollaborationException + */ private void deleteResource(URI uri) throws CollaborationException { HttpClientResponse rsp = executeRequest(new HttpDelete(uri)); // If request was success or resource doesn't exist, we are good @@ -334,6 +460,13 @@ public class CollaborationObjectEventStorage implements } } + /** + * Execute HTTP request + * + * @param request + * @return + * @throws CollaborationException + */ private HttpClientResponse executeRequest(HttpUriRequest request) throws CollaborationException { try { @@ -343,14 +476,30 @@ public class CollaborationObjectEventStorage implements } } + /** + * @param code + * @return true if code is a 200 level return code + */ private boolean isSuccess(int code) { return code >= 200 && code < 300; } + /** + * @param code + * @return true if resource does not exist on server + */ private boolean isNotExists(int code) { return code == 404 || code == 410; } + /** + * @deprecated this error is related to MKCOL. MKCOL is only required for + * DAV (pre 14.3) + * + * @param code + * @return true if directory alread exists on server + */ + @Deprecated private boolean isDirExists(int code) { return code == 405 || code == 301; } diff --git a/edexOsgi/com.raytheon.uf.common.comm/src/com/raytheon/uf/common/comm/HttpClient.java b/edexOsgi/com.raytheon.uf.common.comm/src/com/raytheon/uf/common/comm/HttpClient.java index c976047937..8577585857 100644 --- a/edexOsgi/com.raytheon.uf.common.comm/src/com/raytheon/uf/common/comm/HttpClient.java +++ b/edexOsgi/com.raytheon.uf.common.comm/src/com/raytheon/uf/common/comm/HttpClient.java @@ -104,6 +104,7 @@ import com.raytheon.uf.common.util.ByteArrayOutputStreamPool.ByteArrayOutputStre * Mar 11, 2013 1786 mpduff Add https capability. * Jun 12, 2013 2102 njensen Better error handling when using * DynamicSerializeStreamHandler + * Feb 17, 2014 2756 bclement added content type to response object * * * @@ -116,9 +117,12 @@ public class HttpClient { public final byte[] data; - private HttpClientResponse(int code, byte[] data) { + public final String contentType; + + private HttpClientResponse(int code, byte[] data, String contentType) { this.code = code; this.data = data != null ? data : new byte[0]; + this.contentType = contentType; } } @@ -676,7 +680,7 @@ public class HttpClient { byteResult = ((DefaultInternalStreamHandler) handlerCallback).byteResult; } return new HttpClientResponse(resp.getStatusLine().getStatusCode(), - byteResult); + byteResult, getContentType(resp)); } finally { if (ongoing != null) { ongoing.decrementAndGet(); @@ -684,6 +688,24 @@ public class HttpClient { } } + /** + * Get content type of response + * + * @param response + * @return null if none found + */ + private static String getContentType(HttpResponse response) { + String rval = null; + HttpEntity entity = response.getEntity(); + if (entity != null) { + Header contentType = entity.getContentType(); + if (contentType != null) { + rval = contentType.getValue(); + } + } + return rval; + } + /** * Streams the response content to the handler callback and closes the http * connection once finished. diff --git a/edexOsgi/com.raytheon.uf.common.http/.classpath b/edexOsgi/com.raytheon.uf.common.http/.classpath new file mode 100644 index 0000000000..ad32c83a78 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.http/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/edexOsgi/com.raytheon.uf.common.http/.project b/edexOsgi/com.raytheon.uf.common.http/.project new file mode 100644 index 0000000000..1edb416079 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.http/.project @@ -0,0 +1,28 @@ + + + com.raytheon.uf.common.http + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/edexOsgi/com.raytheon.uf.common.http/.settings/org.eclipse.jdt.core.prefs b/edexOsgi/com.raytheon.uf.common.http/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..c537b63063 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.http/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/edexOsgi/com.raytheon.uf.common.http/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.http/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..59585c3fa7 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.http/META-INF/MANIFEST.MF @@ -0,0 +1,9 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Common Http +Bundle-SymbolicName: com.raytheon.uf.common.http +Bundle-Version: 1.14.0 +Bundle-Vendor: RAYTHEON +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Export-Package: com.raytheon.uf.common.http +Require-Bundle: org.apache.commons.lang;bundle-version="2.3.0" diff --git a/edexOsgi/com.raytheon.uf.common.http/build.properties b/edexOsgi/com.raytheon.uf.common.http/build.properties new file mode 100644 index 0000000000..34d2e4d2da --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.http/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/AcceptHeaderParser.java b/edexOsgi/com.raytheon.uf.common.http/src/com/raytheon/uf/common/http/AcceptHeaderParser.java similarity index 93% rename from edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/AcceptHeaderParser.java rename to edexOsgi/com.raytheon.uf.common.http/src/com/raytheon/uf/common/http/AcceptHeaderParser.java index 981b7e7f09..0fa56fad41 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/AcceptHeaderParser.java +++ b/edexOsgi/com.raytheon.uf.common.http/src/com/raytheon/uf/common/http/AcceptHeaderParser.java @@ -17,14 +17,14 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.edex.ogc.common.http; +package com.raytheon.uf.common.http; import java.util.Iterator; import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * Parses Accept-Encoding headers for HTTP requests + * Parses Accept and Accept-Encoding headers for HTTP requests * *
  * 
@@ -33,6 +33,7 @@ import java.util.regex.Pattern;
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Nov 8, 2013  2539       bclement     Initial creation
+ * Feb 14, 2014 2756       bclement     moved to common http from ogc common
  * 
  * 
* diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/AcceptHeaderValue.java b/edexOsgi/com.raytheon.uf.common.http/src/com/raytheon/uf/common/http/AcceptHeaderValue.java similarity index 94% rename from edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/AcceptHeaderValue.java rename to edexOsgi/com.raytheon.uf.common.http/src/com/raytheon/uf/common/http/AcceptHeaderValue.java index 1df92f26d9..091ce531c1 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/AcceptHeaderValue.java +++ b/edexOsgi/com.raytheon.uf.common.http/src/com/raytheon/uf/common/http/AcceptHeaderValue.java @@ -17,7 +17,7 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.uf.edex.ogc.common.http; +package com.raytheon.uf.common.http; /** * Represents a single HTTP accept(-encoding) header encoding with weight value @@ -29,6 +29,7 @@ package com.raytheon.uf.edex.ogc.common.http; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Nov 8, 2013 2539 bclement Initial creation + * Feb 14, 2014 2756 bclement moved to common http from ogc common * * * diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/MimeType.java b/edexOsgi/com.raytheon.uf.common.http/src/com/raytheon/uf/common/http/MimeType.java similarity index 89% rename from edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/MimeType.java rename to edexOsgi/com.raytheon.uf.common.http/src/com/raytheon/uf/common/http/MimeType.java index 33f50f5c9b..4f2a8ced8c 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/MimeType.java +++ b/edexOsgi/com.raytheon.uf.common.http/src/com/raytheon/uf/common/http/MimeType.java @@ -7,7 +7,7 @@ * in and to this copyrighted software are as specified in DFARS * 252.227-7014 which was made part of the above contract. */ -package com.raytheon.uf.edex.ogc.common.http; +package com.raytheon.uf.common.http; import java.util.Collections; import java.util.LinkedHashMap; @@ -18,7 +18,7 @@ import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; /** - * Data object representing a MIME type used in service requests + * Data object representing a MIME type used in http requests * *
  * 
@@ -27,6 +27,7 @@ import org.apache.commons.lang.StringUtils;
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Oct 29, 2012            bclement     Initial creation
+ * Feb 14, 2014 2756       bclement     moved to common http from ogc common
  * 
  * 
* @@ -50,6 +51,9 @@ public class MimeType { private static final Pattern PARAM_PATTERN = Pattern.compile(";\\s*(" + TOKEN_CLASS + "+)=(" + TOKEN_CLASS + "+|\"\\S+\")"); + /** + * @param mime + */ public MimeType(String mime){ Matcher m = TYPE_PATTERN.matcher(mime); if (m.matches()) { @@ -70,6 +74,12 @@ public class MimeType { } } + /** + * Parse parameter string into name/value pairs + * + * @param paramStr + * @return + */ private static Map getParameters(String paramStr) { Matcher m = PARAM_PATTERN.matcher(paramStr); Map rval = new LinkedHashMap(); @@ -141,6 +151,10 @@ public class MimeType { return true; } + /** + * @param other + * @return true if the mime type equals this one ignoring any parameters + */ public boolean equalsIgnoreParams(MimeType other) { if (other == null) { return false; @@ -166,10 +180,18 @@ public class MimeType { return parameters.get(paramName.toLowerCase()); } + /** + * @return the number of parameters this mime type has + */ public int getNumParams() { return parameters.size(); } + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ @Override public String toString(){ StringBuilder sb = new StringBuilder(toStringWithoutParams()); @@ -186,6 +208,11 @@ public class MimeType { return sb.toString(); } + /** + * Format mime type excluding any parameters + * + * @return + */ public String toStringWithoutParams() { StringBuilder sb = new StringBuilder(); sb.append(this.type).append("/"); diff --git a/edexOsgi/com.raytheon.uf.edex.datadelivery.core.feature/feature.xml b/edexOsgi/com.raytheon.uf.edex.datadelivery.core.feature/feature.xml index a1946d64c8..af458efd8f 100644 --- a/edexOsgi/com.raytheon.uf.edex.datadelivery.core.feature/feature.xml +++ b/edexOsgi/com.raytheon.uf.edex.datadelivery.core.feature/feature.xml @@ -143,4 +143,11 @@ version="0.0.0" unpack="false"/> + + diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.ogc.common/META-INF/MANIFEST.MF index 7563474b8c..5574836c33 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/META-INF/MANIFEST.MF @@ -22,7 +22,8 @@ Require-Bundle: net.opengis;bundle-version="1.0.2", org.apache.commons.cxf, org.eclipse.jetty;bundle-version="7.6.9", com.raytheon.uf.common.dataplugin.level;bundle-version="1.12.1174", - com.raytheon.uf.edex.log;bundle-version="1.12.1174" + com.raytheon.uf.edex.log;bundle-version="1.12.1174", + com.raytheon.uf.common.http Export-Package: com.raytheon.uf.edex.ogc.common, com.raytheon.uf.edex.ogc.common.db, com.raytheon.uf.edex.ogc.common.feature, diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcResponse.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcResponse.java index c0fc6fd769..5294a03f48 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcResponse.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/OgcResponse.java @@ -19,7 +19,7 @@ **/ package com.raytheon.uf.edex.ogc.common; -import com.raytheon.uf.edex.ogc.common.http.MimeType; +import com.raytheon.uf.common.http.MimeType; /** * Response wrapper for OGC web services diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/GmlUtils.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/GmlUtils.java index 8e49e4ed45..a200a4be7a 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/GmlUtils.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/GmlUtils.java @@ -14,9 +14,9 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.raytheon.uf.common.http.MimeType; import com.raytheon.uf.edex.ogc.common.InvalidVersionException; import com.raytheon.uf.edex.ogc.common.Version; -import com.raytheon.uf.edex.ogc.common.http.MimeType; /** * Utility methods and constants for GML version parsing and comparison diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/JsonFeatureFormatter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/JsonFeatureFormatter.java index 9b3c22e3e7..2eda8b9393 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/JsonFeatureFormatter.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/JsonFeatureFormatter.java @@ -29,12 +29,12 @@ import org.geotools.feature.FeatureCollection; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; +import com.raytheon.uf.common.http.MimeType; import com.raytheon.uf.common.json.geo.GeoJsonUtil; import com.raytheon.uf.common.json.geo.GeoJsonUtilSimpleImpl; import com.raytheon.uf.common.json.geo.MixedFeatureCollection; import com.raytheon.uf.edex.ogc.common.OgcResponse; import com.raytheon.uf.edex.ogc.common.OgcResponse.TYPE; -import com.raytheon.uf.edex.ogc.common.http.MimeType; /** diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/ShpFeatureFormatter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/ShpFeatureFormatter.java index 29eddb7e20..89c9fe9cf9 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/ShpFeatureFormatter.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/ShpFeatureFormatter.java @@ -47,11 +47,11 @@ import org.opengis.feature.simple.SimpleFeatureType; import sun.misc.IOUtils; +import com.raytheon.uf.common.http.MimeType; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.edex.ogc.common.OgcResponse; import com.raytheon.uf.edex.ogc.common.OgcResponse.TYPE; -import com.raytheon.uf.edex.ogc.common.http.MimeType; /** * Convert simple features to shape files diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/SimpleFeatureFormatter.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/SimpleFeatureFormatter.java index 44751fa6eb..7ac3266dd8 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/SimpleFeatureFormatter.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/feature/SimpleFeatureFormatter.java @@ -24,8 +24,8 @@ import java.util.List; import org.opengis.feature.simple.SimpleFeature; +import com.raytheon.uf.common.http.MimeType; import com.raytheon.uf.edex.ogc.common.OgcResponse; -import com.raytheon.uf.edex.ogc.common.http.MimeType; /** * Interface for converting simple features to different output formats diff --git a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/OgcHttpHandler.java b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/OgcHttpHandler.java index f84c194ba6..52e0831b4e 100644 --- a/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/OgcHttpHandler.java +++ b/edexOsgi/com.raytheon.uf.edex.ogc.common/src/com/raytheon/uf/edex/ogc/common/http/OgcHttpHandler.java @@ -38,6 +38,9 @@ import javax.xml.stream.XMLStreamReader; import org.apache.commons.collections.map.CaseInsensitiveMap; import org.apache.commons.lang.StringUtils; +import com.raytheon.uf.common.http.AcceptHeaderParser; +import com.raytheon.uf.common.http.AcceptHeaderValue; +import com.raytheon.uf.common.http.MimeType; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.edex.ogc.common.OgcException; diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.edex.wfs/META-INF/MANIFEST.MF index 6211253e8d..4b2197fa04 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.edex.wfs/META-INF/MANIFEST.MF @@ -25,7 +25,8 @@ Require-Bundle: org.geotools;bundle-version="2.6.4", org.w3.xmlschema;bundle-version="1.0.0", com.raytheon.uf.common.pointdata;bundle-version="1.12.1174", org.apache.commons.collections;bundle-version="3.2.0", - org.apache.commons.cxf;bundle-version="1.0.0" + org.apache.commons.cxf;bundle-version="1.0.0", + com.raytheon.uf.common.http Export-Package: com.raytheon.uf.edex.wfs, com.raytheon.uf.edex.wfs.feature, com.raytheon.uf.edex.wfs.filter, diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/AbstractWfsProvider.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/AbstractWfsProvider.java index 768b812bcd..2cefd3b385 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/AbstractWfsProvider.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/provider/AbstractWfsProvider.java @@ -22,6 +22,7 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.raytheon.uf.common.http.MimeType; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.edex.ogc.common.OgcBoundingBox; @@ -30,7 +31,6 @@ import com.raytheon.uf.edex.ogc.common.OgcNamespace; import com.raytheon.uf.edex.ogc.common.OgcPrefix; import com.raytheon.uf.edex.ogc.common.OgcResponse; import com.raytheon.uf.edex.ogc.common.OgcTimeRange; -import com.raytheon.uf.edex.ogc.common.http.MimeType; import com.raytheon.uf.edex.ogc.common.http.OgcHttpHandler; import com.raytheon.uf.edex.ogc.common.output.IOgcHttpResponse; import com.raytheon.uf.edex.ogc.common.output.OgcResponseOutput; diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/GetFeatureReq.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/GetFeatureReq.java index 0bd73f38ec..665367f8f8 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/GetFeatureReq.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/GetFeatureReq.java @@ -36,7 +36,7 @@ import net.opengis.wfs.v_1_1_0.ResultTypeType; import net.opengis.wfs.v_2_0_0.GetPropertyValueType; import net.opengis.wfs.v_2_0_0.StoredQueryType; -import com.raytheon.uf.edex.ogc.common.http.MimeType; +import com.raytheon.uf.common.http.MimeType; import com.raytheon.uf.edex.wfs.WfsException; import com.raytheon.uf.edex.wfs.WfsException.Code; import com.raytheon.uf.edex.wfs.querystore.IStoredQueryCallback; diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/WfsRequest.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/WfsRequest.java index f7c1114d0a..9f6ffd2f83 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/WfsRequest.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/request/WfsRequest.java @@ -19,8 +19,8 @@ **/ package com.raytheon.uf.edex.wfs.request; +import com.raytheon.uf.common.http.MimeType; import com.raytheon.uf.edex.ogc.common.OgcResponse; -import com.raytheon.uf.edex.ogc.common.http.MimeType; /** * Abstract base for WFS request wrappers diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/Capabilities.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/Capabilities.java index f019f9739f..c977adafc0 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/Capabilities.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/Capabilities.java @@ -56,11 +56,11 @@ import net.opengis.wfs.v_1_1_0.GMLObjectTypeType; import net.opengis.wfs.v_1_1_0.OutputFormatListType; import net.opengis.wfs.v_1_1_0.WFSCapabilitiesType; +import com.raytheon.uf.common.http.MimeType; import com.raytheon.uf.edex.ogc.common.OgcNamespace; import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; import com.raytheon.uf.edex.ogc.common.feature.GmlUtils; -import com.raytheon.uf.edex.ogc.common.http.MimeType; import com.raytheon.uf.edex.wfs.IWfsProvider.WfsOpType; import com.raytheon.uf.edex.wfs.WfsException; import com.raytheon.uf.edex.wfs.reg.WfsRegistryImpl; diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/Wfs1_1_0Provider.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/Wfs1_1_0Provider.java index b2e2276e1b..3c4a4f75e0 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/Wfs1_1_0Provider.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v1_1_0/Wfs1_1_0Provider.java @@ -45,6 +45,7 @@ import org.opengis.feature.simple.SimpleFeature; import org.springframework.context.ApplicationContext; import org.w3.xmlschema.Schema; +import com.raytheon.uf.common.http.MimeType; import com.raytheon.uf.edex.core.EDEXUtil; import com.raytheon.uf.edex.ogc.common.OgcException; import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; @@ -55,7 +56,6 @@ import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; import com.raytheon.uf.edex.ogc.common.feature.GmlUtils; import com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter; import com.raytheon.uf.edex.ogc.common.http.EndpointInfo; -import com.raytheon.uf.edex.ogc.common.http.MimeType; import com.raytheon.uf.edex.ogc.common.http.OgcHttpHandler; import com.raytheon.uf.edex.ogc.common.output.IOgcHttpResponse; import com.raytheon.uf.edex.ogc.common.output.OgcResponseOutput; diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/Capabilities.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/Capabilities.java index a1a7af2c2d..79b6b0784f 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/Capabilities.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/Capabilities.java @@ -54,11 +54,11 @@ import net.opengis.wfs.v_2_0_0.FeatureTypeListType; import net.opengis.wfs.v_2_0_0.FeatureTypeType; import net.opengis.wfs.v_2_0_0.WFSCapabilitiesType; +import com.raytheon.uf.common.http.MimeType; import com.raytheon.uf.edex.ogc.common.OgcNamespace; import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; import com.raytheon.uf.edex.ogc.common.feature.GmlUtils; -import com.raytheon.uf.edex.ogc.common.http.MimeType; import com.raytheon.uf.edex.wfs.IWfsProvider.WfsOpType; import com.raytheon.uf.edex.wfs.WfsException; import com.raytheon.uf.edex.wfs.reg.WfsRegistryImpl; diff --git a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/Wfs2_0_0Provider.java b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/Wfs2_0_0Provider.java index 079269dd49..afa2484116 100644 --- a/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/Wfs2_0_0Provider.java +++ b/edexOsgi/com.raytheon.uf.edex.wfs/src/com/raytheon/uf/edex/wfs/v2_0_0/Wfs2_0_0Provider.java @@ -67,6 +67,7 @@ import org.w3.xmlschema.Schema; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import com.raytheon.uf.common.http.MimeType; import com.raytheon.uf.edex.core.EDEXUtil; import com.raytheon.uf.edex.ogc.common.OgcException; import com.raytheon.uf.edex.ogc.common.OgcOperationInfo; @@ -77,7 +78,6 @@ import com.raytheon.uf.edex.ogc.common.OgcServiceInfo; import com.raytheon.uf.edex.ogc.common.feature.GmlUtils; import com.raytheon.uf.edex.ogc.common.feature.SimpleFeatureFormatter; import com.raytheon.uf.edex.ogc.common.http.EndpointInfo; -import com.raytheon.uf.edex.ogc.common.http.MimeType; import com.raytheon.uf.edex.ogc.common.http.OgcHttpHandler; import com.raytheon.uf.edex.ogc.common.output.IOgcHttpResponse; import com.raytheon.uf.edex.ogc.common.output.OgcResponseOutput; diff --git a/javaUtilities/collaboration.dataserver/.classpath b/javaUtilities/collaboration.dataserver/.classpath new file mode 100644 index 0000000000..ad32c83a78 --- /dev/null +++ b/javaUtilities/collaboration.dataserver/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/javaUtilities/collaboration.dataserver/.project b/javaUtilities/collaboration.dataserver/.project new file mode 100644 index 0000000000..0d05171a15 --- /dev/null +++ b/javaUtilities/collaboration.dataserver/.project @@ -0,0 +1,28 @@ + + + collaboration.dataserver + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/javaUtilities/collaboration.dataserver/.settings/org.eclipse.jdt.core.prefs b/javaUtilities/collaboration.dataserver/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..c537b63063 --- /dev/null +++ b/javaUtilities/collaboration.dataserver/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/javaUtilities/collaboration.dataserver/META-INF/MANIFEST.MF b/javaUtilities/collaboration.dataserver/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..d6f3591a3d --- /dev/null +++ b/javaUtilities/collaboration.dataserver/META-INF/MANIFEST.MF @@ -0,0 +1,10 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Dataserver +Bundle-SymbolicName: collaboration.dataserver +Bundle-Version: 1.14.0 +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Require-Bundle: org.eclipse.jetty, + com.raytheon.uf.common.util, + org.jivesoftware.smack, + com.raytheon.uf.common.http diff --git a/javaUtilities/collaboration.dataserver/build.properties b/javaUtilities/collaboration.dataserver/build.properties new file mode 100644 index 0000000000..34d2e4d2da --- /dev/null +++ b/javaUtilities/collaboration.dataserver/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/javaUtilities/collaboration.dataserver/config/credentials.properties b/javaUtilities/collaboration.dataserver/config/credentials.properties new file mode 100644 index 0000000000..ea8c19fb13 --- /dev/null +++ b/javaUtilities/collaboration.dataserver/config/credentials.properties @@ -0,0 +1,2 @@ +xmpp.username=dataserver +xmpp.password=password \ No newline at end of file diff --git a/javaUtilities/collaboration.dataserver/config/settings.properties b/javaUtilities/collaboration.dataserver/config/settings.properties new file mode 100644 index 0000000000..30cf8802a1 --- /dev/null +++ b/javaUtilities/collaboration.dataserver/config/settings.properties @@ -0,0 +1,5 @@ +port=9682 +datapath=/session_data/ +logdir=logs +logname=serverlog_yyyy_mm_dd.log +xmpp.server=localhost diff --git a/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/Config.java b/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/Config.java new file mode 100644 index 0000000000..391ac66579 --- /dev/null +++ b/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/Config.java @@ -0,0 +1,273 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.collaboration.dataserver; + +import java.io.File; +import java.io.FileInputStream; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Properties; + +/** + * Global configuration for dataserver + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 5, 2014  2756      bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class Config{ + + public static final String HOST_KEY = "host"; + + public static final String PORT_KEY = "port"; + + public static final int PORT_DEFAULT = 9682; + + public static final String DATAPATH_KEY = "datapath"; + + public static final String DATAPATH_DEFAULT = "/session_data/"; + + public static final String LOGDIR_KEY = "logdir"; + + public static final String LOGDIR_DEFAULT = "logs"; + + public static final String LOGNAME_KEY = "logname"; + + public static final String LOGNAME_DEFAULT = "serverlog_yyyy_mm_dd.log"; + + public static final String STOREDIR_KEY = "storedir"; + + public static final String STOREDIR_DEFAULT = "store"; + + public static final String LEGACY_MODE_KEY = "legacy.mode"; + + public static final boolean LEGACY_MODE_DEFAULT = true; + + public static final String XMPP_USERNAME_KEY = "xmpp.username"; + + public static final String XMPP_PASSWORD_KEY = "xmpp.password"; + + public static final String XMPP_SERVER_KEY = "xmpp.server"; + + public static final String XMPP_SERVER_DEFAULT = "localhost"; + + public static final String config = System.getProperty( + "collaboration.dataserver.config", "config/settings.properties"); + + public static final String credentialsFile = System.getProperty( + "collaboration.dataserver.credentials", + "config/credentials.properties"); + + public static final Boolean useStdOut = Boolean + .getBoolean("collaboration.dataserver.stdout"); + + private static Properties _props = null; + + private static Properties _credProps = null; + + private Config() { + } + + /** + * Get cached properties. Loads if not initialized. + * + * @return + */ + private static synchronized Properties getProperties() { + if (_props == null) { + _props = new Properties(); + loadProperties(_props, config, false); + } + + return _props; + } + + /** + * Get cached credentials properties. Loads if not initialized. + * + * @return + */ + private static synchronized Properties getCredProperties() + throws RuntimeException { + if (_credProps == null) { + _credProps = new Properties(); + loadProperties(_credProps, credentialsFile, true); + } + + return _credProps; + } + + /** + * Loads properties from file system. If fatal is true, runtime exception is + * thrown on error. Otherwise, an error message is logged and defaults are + * used. + * + * @param props + * @param propertyFile + * @param fatal + */ + private static void loadProperties(Properties props, String propertyFile, + boolean fatal) throws RuntimeException { + try { + props.load(new FileInputStream(new File(propertyFile))); + } catch (Exception e) { + System.err.println("Unable to open properties file: " + + propertyFile + ". " + e.getLocalizedMessage()); + if (fatal) { + throw new RuntimeException( + "Unable to continue without configuration: " + + propertyFile, e); + } else { + e.printStackTrace(); + System.err.println("Continuing using defaults"); + } + } + } + + /** + * Get integer value from properties + * + * @param key + * @param defaultValue + * @return + */ + public static int getInt(String key, int defaultValue) { + Properties props = getProperties(); + String value = props.getProperty(key); + if (value == null) { + return defaultValue; + } else { + return Integer.parseInt(value); + } + } + + /** + * Get string value from properties + * + * @param key + * @param defaultValue + * @return + */ + public static String getProp(String key, String defaultValue) { + return getProperties().getProperty(key, defaultValue); + } + + /** + * Get boolean value from properties + * + * @param key + * @param defaultValue + * @return + */ + public static boolean getBool(String key, boolean defaultValue) { + Properties props = getProperties(); + String value = props.getProperty(key); + if (value == null) { + return defaultValue; + } else { + return Boolean.parseBoolean(value); + } + } + + /** + * @return username for XMPP account + * @throws RuntimeException + * if configuration for username cannot be found + */ + public static String getXmppUsername() throws RuntimeException { + return getRequiredCredential(XMPP_USERNAME_KEY); + } + + /** + * @return password for XMPP account + * @throws RuntimeException + * if configuration for password cannot be found + */ + public static String getXmppPassword() throws RuntimeException { + return getRequiredCredential(XMPP_PASSWORD_KEY); + } + + /** + * Get property that represents a web service path. Ensures a slash begins + * and ends the path. + * + * @param key + * @param defaultValue + * @return + */ + public static String getPath(String key, String defaultValue) { + String path = getProp(key, defaultValue).trim(); + if (!path.startsWith("/")) { + path = "/" + path; + } + if (!path.endsWith("/")) { + path = path + "/"; + } + return path; + } + + /** + * Get property from credentials file + * + * @param key + * @return + * @throws RuntimeException + * if credential configuration cannot be found + */ + private static String getRequiredCredential(String key) + throws RuntimeException { + Properties credProperties = getCredProperties(); + String rval = credProperties.getProperty(key); + if (rval == null) { + throw new RuntimeException( + "Missing required credentials property: " + key); + } + return rval; + } + + /** + * Get URL for data service. If host portion of URL is not found in config, + * this method will attempt to determine the canonical hostname for the + * machine + * + * @return + * @throws UnknownHostException + */ + public static String getDataserverUrl() throws UnknownHostException { + Properties props = getProperties(); + String host = props.getProperty(HOST_KEY); + if (host == null) { + host = InetAddress.getLocalHost().getCanonicalHostName(); + } + int port = getInt(PORT_KEY, PORT_DEFAULT); + String datapath = getPath(DATAPATH_KEY, DATAPATH_DEFAULT); + return "http://" + host + ":" + port + datapath; + } + +} diff --git a/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/DataService.java b/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/DataService.java new file mode 100644 index 0000000000..bacebcca64 --- /dev/null +++ b/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/DataService.java @@ -0,0 +1,236 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.collaboration.dataserver; + +import java.io.File; +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +import com.raytheon.uf.common.http.AcceptHeaderParser; +import com.raytheon.uf.common.http.AcceptHeaderValue; + +/** + * Servlet for storing and retrieving collaboration data objects + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 5, 2014  2756      bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class DataService extends HttpServlet { + + private static final long serialVersionUID = 3828421078339628468L; + + private final File base; + + private final FileManager manager; + + private final Logger log = Log.getLogger(this.getClass()); + + public static final String XML_CONTENT_TYPE = "text/xml"; + + public static final String HTML_CONTENT_TYPE = "text/html"; + + public static final String BINARY_CONTENT_TYPE = "application/octet-stream"; + + public static final String ACCEPT_HEADER = "accept"; + + private final boolean legacyMode; + + /** + * @param base + * base storage directory + */ + public DataService(File base) { + this.base = base; + if (!base.exists()) { + if (!base.mkdirs()) { + throw new IllegalStateException( + "Unable to create storage base directory: " + + base.getAbsolutePath()); + } + } + this.manager = new FileManager(base); + this.legacyMode = Config.getBool(Config.LEGACY_MODE_KEY, + Config.LEGACY_MODE_DEFAULT); + } + + /** + * + */ + public DataService() { + this(new File(Config.getProp(Config.STOREDIR_KEY, + Config.STOREDIR_DEFAULT))); + } + + /* + * (non-Javadoc) + * + * @see + * javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest + * , javax.servlet.http.HttpServletResponse) + */ + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + try { + File file = getFile(req); + if (!file.exists()) { + throw new RestException(HttpServletResponse.SC_NOT_FOUND, + "No Such Resource: " + file.getAbsolutePath()); + } + ServletOutputStream out = resp.getOutputStream(); + if (file.isDirectory()) { + if (acceptsXml(req)) { + resp.setContentType(XML_CONTENT_TYPE); + manager.readDirectoryAsXml(file, out); + } else { + resp.setContentType(HTML_CONTENT_TYPE); + manager.readDirectoryAsHtml(file, out); + } + } else { + resp.setContentType(BINARY_CONTENT_TYPE); + manager.readFile(file, out); + } + } catch (IOException e) { + log.warn("Problem handling GET", e); + resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } catch (RestException e) { + log.debug(e.getLocalizedMessage(), e); + resp.sendError(e.getCode()); + } + } + + /** + * @param req + * @return true if request has an accepts header that lists xml content type + */ + private boolean acceptsXml(HttpServletRequest req) { + String header = req.getHeader(ACCEPT_HEADER); + if (header == null || header.trim().isEmpty()) { + return false; + } + for (AcceptHeaderValue value : new AcceptHeaderParser(header)) { + String type = value.getEncoding(); + if (type.equalsIgnoreCase(XML_CONTENT_TYPE) && value.isAcceptable()) { + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * javax.servlet.http.HttpServlet#doPut(javax.servlet.http.HttpServletRequest + * , javax.servlet.http.HttpServletResponse) + */ + @Override + protected void doPut(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + // TODO auth + try { + File file = getFile(req); + manager.writeFile(req.getInputStream(), file); + } catch (IOException e) { + log.warn("Problem handling PUT", e); + resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } catch (RestException e) { + log.debug(e.getLocalizedMessage(), e); + resp.sendError(e.getCode()); + } + } + + /** + * Create file object from request path + * + * @param req + * @return + */ + private File getFile(HttpServletRequest req) { + String pathInfo = req.getPathInfo(); + return new File(base, pathInfo); + } + + /* + * (non-Javadoc) + * + * @see + * javax.servlet.http.HttpServlet#doDelete(javax.servlet.http.HttpServletRequest + * , javax.servlet.http.HttpServletResponse) + */ + @Override + protected void doDelete(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + // TODO auth + try { + File file = getFile(req); + if (!file.exists()) { + throw new RestException(HttpServletResponse.SC_NOT_FOUND, + "No Such Resource: " + file.getAbsolutePath()); + } + manager.delete(file); + } catch (IOException e) { + log.warn("Problem handling DELETE", e); + resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } catch (RestException e) { + log.debug(e.getLocalizedMessage(), e); + resp.sendError(e.getCode()); + } + } + + /* + * (non-Javadoc) + * + * @see + * javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest + * , javax.servlet.http.HttpServletResponse) + */ + @Override + protected void service(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + String method = req.getMethod(); + // clients before 14.3 used DAV which uses MKCOL. This isn't needed + // since we create directories on put. + if (legacyMode && "MKCOL".equalsIgnoreCase(method)) { + resp.setStatus(HttpServletResponse.SC_OK); + return; + } + super.service(req, resp); + } + +} diff --git a/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/DataserverMain.java b/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/DataserverMain.java new file mode 100644 index 0000000000..41268f2fbc --- /dev/null +++ b/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/DataserverMain.java @@ -0,0 +1,129 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.collaboration.dataserver; + +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.util.TimeZone; + +import org.eclipse.jetty.util.RolloverFileOutputStream; + +/** + * Entry class for dataserver + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 5, 2014  2756      bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class DataserverMain { + + private static final int CONNECTION_DELAY = 10000; // 10 seconds + + private static final int SHUTDOWN_DELAY = 1000; // 1 second + + /** + * @param args + * @throws IOException + */ + public static void main(String[] args) throws IOException { + try { + configureLogging(); + } catch (IOException e) { + System.err.println("Unable to configure logging: " + + e.getLocalizedMessage()); + System.err + .println("Continuing using standard out and standard error"); + } + final XmppServerConnection xmppConnection; + try { + xmppConnection = new XmppServerConnection(); + } catch (Exception e) { + System.err + .println("Unable to connect to XMPP server, shutting down"); + e.printStackTrace(); + return; + } + final WebServerRunner webServer = new WebServerRunner(); + new Thread(webServer).start(); + wait(CONNECTION_DELAY); + new Thread(xmppConnection).start(); + Runtime.getRuntime().addShutdownHook(new Thread() { + public void run() { + System.out.println("Server shutting down"); + xmppConnection.disconnect(); + webServer.stop(); + DataserverMain.wait(SHUTDOWN_DELAY); + } + }); + } + + /** + * sleep thread for specified milliseconds + * + * @param millis + */ + private static void wait(int millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + /** + * Set up rolling file log unless standard out is to be used + * + * @throws IOException + */ + private static void configureLogging() throws IOException { + if (Config.useStdOut){ + return; + } + File logDir = new File(Config.getProp(Config.LOGDIR_KEY, Config.LOGDIR_DEFAULT)); + if ( !logDir.exists()){ + if (!logDir.mkdirs()) { + throw new IOException( + "Unable to create configured logging directory: " + + logDir.getAbsolutePath()); + } + } else if (!logDir.isDirectory()){ + throw new IOException( + "Configured logging directory exists but is not a directory: " + + logDir.getAbsolutePath()); + } + String logFileName = logDir.getAbsolutePath() + File.separator + + Config.getProp(Config.LOGNAME_KEY, Config.LOGNAME_DEFAULT); + RolloverFileOutputStream out = new RolloverFileOutputStream( + logFileName, true, 0, TimeZone.getTimeZone("GMT")); + System.setErr(new PrintStream(out)); + System.setOut(new PrintStream(out)); + } + +} diff --git a/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/FileManager.java b/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/FileManager.java new file mode 100644 index 0000000000..9e7387b5a4 --- /dev/null +++ b/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/FileManager.java @@ -0,0 +1,443 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.collaboration.dataserver; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; + +import javax.servlet.http.HttpServletResponse; + +import com.raytheon.uf.common.util.concurrent.KeyLock; +import com.raytheon.uf.common.util.concurrent.KeyLocker; + +/** + * Collaboration event object data storage that uses the file system. Uses a + * read/write lock policy based on file path. The paths are locked from the base + * to the target node and unlocked in reverse order. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 6, 2014  2756      bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class FileManager { + + private static final int BUFFER_SIZE = 1024 * 256; // 256K + + private static final ThreadLocal localBuffer = new ThreadLocal() { + + /* + * (non-Javadoc) + * + * @see java.lang.ThreadLocal#initialValue() + */ + @Override + protected byte[] initialValue() { + return new byte[BUFFER_SIZE]; + } + + }; + + private static final KeyLocker locker = new KeyLocker(); + + private final File base; + + /** + * @param base + * base storage directory + */ + public FileManager(File base) { + this.base = base; + } + + /** + * simple container to associate a file lock with it's access mode + */ + private static class UsedLock { + public final KeyLock lock; + + public final boolean readOnly; + + public UsedLock(KeyLock lock, boolean readOnly) { + this.lock = lock; + this.readOnly = readOnly; + } + } + + /** + * Write inputstream to file system + * + * @param in + * @param file + * @throws IOException + * @throws RestException + */ + public void writeFile(InputStream in, File file) throws IOException, + RestException { + OutputStream out = null; + List locks = null; + KeyLock targetLock = null; + try { + File parent = file.getParentFile(); + // lock all files starting at child of base going to parent + locks = getCreateLocks(parent); + // lock target file for modification + targetLock = locker.getLock(file); + targetLock.lock(); + createDirs(locks); + out = new FileOutputStream(file); + copy(in, out); + } finally { + // unlock in reverse order + if (targetLock != null) { + targetLock.unlock(); + } + unlock(locks); + in.close(); + if (out != null) { + out.flush(); + out.close(); + } + } + } + + /** + * Each item in locks represents a node in a directory path. Attempts to + * create each node in order. + * + * @param locks + * @throws IOException + */ + private void createDirs(List locks) throws IOException { + for (UsedLock lock : locks) { + File f = lock.lock.getKey(); + if (!f.exists()) { + if (!f.mkdir()) { + throw new IOException("Unable to create file: " + + f.getAbsolutePath()); + } + } + } + } + + /** + * Unlock each file lock in reverse order + * + * @param locks + */ + private void unlock(List locks) { + if (locks != null) { + ListIterator iter = locks.listIterator(locks.size()); + while (iter.hasPrevious()) { + UsedLock ul = iter.previous(); + if (ul.readOnly) { + ul.lock.readUnlock(); + } else { + ul.lock.unlock(); + } + } + } + } + + /** + * Get a list of write file locks for each directory from the base to the + * target directory + * + * @param targetDirectory + * @return + * @throws RestException + */ + private List getCreateLocks(File targetDirectory) + throws RestException { + List> locks = new ArrayList>(); + // walk backwards getting locks for each node + while (!base.equals(targetDirectory)) { + locks.add(locker.getLock(targetDirectory)); + targetDirectory = targetDirectory.getParentFile(); + } + List rval = new ArrayList(locks.size()); + // reverse iterate so we lock in the correct order + ListIterator> iter = locks.listIterator(locks.size()); + while (iter.hasPrevious()) { + KeyLock lock = iter.previous(); + File f = lock.getKey(); + if (!f.exists()) { + lock.lock(); + rval.add(new UsedLock(lock, false)); + } else if (f.isDirectory()) { + lock.readLock(); + rval.add(new UsedLock(lock, true)); + } else { + // file exists but is not a directory + throw new RestException(HttpServletResponse.SC_CONFLICT, + "Resource already exists: " + f.getAbsolutePath()); + } + } + return rval; + } + + /** + * Output file to stream + * + * @param file + * @param out + * @throws IOException + * @throws RestException + */ + public void readFile(File file, OutputStream out) throws IOException, + RestException { + InputStream in = null; + List locks = null; + try { + locks = getReadLocks(file); + if ( !file.exists()){ + throw new RestException(HttpServletResponse.SC_NOT_FOUND, + "No Such File: " + file.getAbsoluteFile()); + } + in = new FileInputStream(file); + copy(in, out); + } finally { + unlock(locks); + if (in != null) { + in.close(); + } + out.close(); + } + } + + /** + * Get a list of read only file locks for each file from the base to the + * target file + * + * @param file + * @return + */ + private List getReadLocks(File file) { + List> locks = new ArrayList>(); + // walk backwards getting locks for each node + while (!base.equals(file)) { + locks.add(locker.getLock(file)); + file = file.getParentFile(); + } + List rval = new ArrayList(locks.size()); + // reverse iterate so we lock in the correct order + ListIterator> iter = locks.listIterator(locks.size()); + while (iter.hasPrevious()) { + KeyLock lock = iter.previous(); + lock.readLock(); + rval.add(new UsedLock(lock, true)); + } + return rval; + } + + /** + * Output contents of directory to stream in XML format + * + * @param directory + * @param out + * @throws IOException + * @throws RestException + */ + public void readDirectoryAsXml(File directory, OutputStream out) + throws IOException, RestException { + List locks = null; + Writer w = null; + try { + locks = getReadLocks(directory); + if (!directory.exists()) { + // someone else modified it while waiting for lock + throw new RestException(HttpServletResponse.SC_NOT_FOUND, + "No Such Directory: " + directory.getAbsolutePath()); + } + w = new OutputStreamWriter(out, "UTF-8"); + w.write("\n"); + w.write(""); + for (File f : directory.listFiles()) { + if (f.isDirectory()) { + writeTextTag(w, "Directory", f.getName()); + } else { + writeTextTag(w, "File", f.getName()); + } + } + w.write(""); + } finally { + unlock(locks); + if (w != null) { + w.flush(); + w.close(); + } + } + } + + /** + * Write tag with text element to writer + * + * @param w + * @param tagName + * @param text + * @throws IOException + */ + private void writeTextTag(Writer w, String tagName, String text) + throws IOException { + w.write("<"); + w.write(tagName); + w.write(">"); + w.write(text); + w.write(""); + } + + /** + * Output contents of directory to stream in HTML format + * + * @param directory + * @param out + * @throws IOException + * @throws RestException + */ + public void readDirectoryAsHtml(File directory, OutputStream out) + throws IOException, RestException { + List locks = null; + Writer w = null; + try { + locks = getReadLocks(directory); + if (!directory.exists()) { + // someone else modified it while waiting for lock + throw new RestException(HttpServletResponse.SC_NOT_FOUND, + "No Such Directory: " + directory.getAbsolutePath()); + } + w = new OutputStreamWriter(out, "UTF-8"); + w.write("\n"); + w.write(""); + for (File f : directory.listFiles()) { + String name = f.getName(); + if (f.isDirectory() && !name.endsWith("/")) { + name = name + "/"; + } + writeLinkTag(w, name); + } + w.write(""); + } finally { + unlock(locks); + if (w != null) { + w.flush(); + w.close(); + } + } + } + + /** + * Write html link reference tag to writer + * + * @param w + * @param href + * @throws IOException + */ + private void writeLinkTag(Writer w, String href) throws IOException { + w.write("
"); + w.write(href); + w.write("
"); + } + + /** + * Copy bytes from input to output + * + * @param in + * @param out + * @throws IOException + */ + public static void copy(InputStream in, OutputStream out) + throws IOException { + byte[] buff = localBuffer.get(); + int len; + while ((len = in.read(buff)) != -1) { + out.write(buff, 0, len); + } + } + + /** + * Delete target file and all children + * + * @param file + * @throws IOException + * @throws RestException + */ + public void delete(File file) throws IOException, RestException { + List parentLocks = null; + KeyLock targetLock = null; + try { + File parent = file.getParentFile(); + parentLocks = getReadLocks(parent); + targetLock = locker.getLock(file); + targetLock.lock(); + if (!file.exists()) { + throw new RestException(HttpServletResponse.SC_NOT_FOUND, + "No Such Resource: " + file.getAbsolutePath()); + } + // we don't have to lock children since we have a write lock on the + // directory + deleteRecursive(file); + } finally { + if (targetLock != null) { + targetLock.unlock(); + } + unlock(parentLocks); + } + } + + /** + * Recursive method to delete file and children + * + * @param file + * @throws IOException + */ + private void deleteRecursive(File file) throws IOException { + if (file.isDirectory()) { + for (File sub : file.listFiles()) { + deleteRecursive(sub); + } + } + if (!file.delete()) { + throw new IOException("Unable to delete file: " + + file.getAbsolutePath()); + } + } + +} diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/util/HttpdCollaborationUtil.java b/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/RestException.java similarity index 53% rename from javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/util/HttpdCollaborationUtil.java rename to javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/RestException.java index ce1434d14a..73d6949731 100644 --- a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/util/HttpdCollaborationUtil.java +++ b/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/RestException.java @@ -17,13 +17,10 @@ * See the AWIPS II Master Rights File ("Master Rights File.pdf") for * further licensing information. **/ -package com.raytheon.openfire.plugin.configuration.collaboration.util; - -import java.io.File; +package com.raytheon.collaboration.dataserver; /** - * Various utility methods that are utilized by the Httpd Collaboration plugin - * that do not require a class to be instantiated. + * Exceptions for web service errors to be returned to the client * *
  * 
@@ -31,33 +28,35 @@ import java.io.File;
  * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
- * Aug 07, 2012            bkowal      Initial creation
- * Jan 06, 2013  2563      bclement    removed config preamble
+ * Feb 6, 2014  2756      bclement     Initial creation
  * 
  * 
* - * @author bkowal + * @author bclement * @version 1.0 */ +public class RestException extends Exception{ -public abstract class HttpdCollaborationUtil { - - public static String encodeErrorMessage(Throwable e) { - String content = e.getMessage(); - if (content == null) { - // final attempt - content = e.toString(); - } - - return "error : " + content; - } - - public static String endPathIfNecessary(String _path) { - if (_path.endsWith(File.separator)) { - return _path; - } - - return _path + File.separator; + private static final long serialVersionUID = -3940227418233750698L; + + private final int code; + + + /** + * @param code + * http status code + * @param message + */ + public RestException(int code, String message) { + super(message); + this.code = code; } -} \ No newline at end of file + /** + * @return the code + */ + public int getCode() { + return code; + } + +} diff --git a/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/WebServerRunner.java b/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/WebServerRunner.java new file mode 100644 index 0000000000..08f251d796 --- /dev/null +++ b/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/WebServerRunner.java @@ -0,0 +1,93 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.collaboration.dataserver; + +import java.io.File; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; + +/** + * Start and run jetty webserver + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 14, 2014 2756       bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class WebServerRunner implements Runnable { + + private Server server; + + /* (non-Javadoc) + * @see java.lang.Runnable#run() + */ + @Override + public void run() { + server = new Server(Config.getInt(Config.PORT_KEY, + Config.PORT_DEFAULT)); + + ServletContextHandler context = new ServletContextHandler( + ServletContextHandler.SESSIONS); + context.setContextPath("/"); + server.setHandler(context); + + File base = new File(Config.getProp(Config.STOREDIR_KEY, + Config.STOREDIR_DEFAULT)); + if (!base.exists()) { + base.mkdirs(); + } + + String datapath = Config.getPath(Config.DATAPATH_KEY, + Config.DATAPATH_DEFAULT); + context.addServlet(new ServletHolder(new DataService(base)), datapath + + "*"); + try { + server.start(); + System.out.println("Server started"); + server.join(); + } catch (Exception e) { + System.err.println("Unable to start web server"); + e.printStackTrace(); + } + } + + /** + * Shutdown web server + */ + public void stop() { + try { + server.stop(); + } catch (Exception e) { + System.err.println("Unable to stop web server"); + e.printStackTrace(); + } + } + +} diff --git a/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/XmppServerConnection.java b/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/XmppServerConnection.java new file mode 100644 index 0000000000..42413b23a6 --- /dev/null +++ b/javaUtilities/collaboration.dataserver/src/com/raytheon/collaboration/dataserver/XmppServerConnection.java @@ -0,0 +1,135 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.collaboration.dataserver; + +import java.net.UnknownHostException; + +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.jivesoftware.smack.PacketListener; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.filter.PacketFilter; +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.packet.IQ.Type; +import org.jivesoftware.smack.packet.Packet; +import org.jivesoftware.smack.util.SyncPacketSend; + +/** + * Starts and runs XMPP client thread for communication with XMPP server + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 14, 2014 2756       bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class XmppServerConnection implements Runnable { + + private static final int PACKET_SEND_TIMEOUT = 5000; // 5 seconds + + private final XMPPConnection conn; + + private final String user; + + private final String password; + + private final String xmppServerAddress; + + private final String dataServerUrl; + + private final Logger log = Log.getLogger(this.getClass()); + + /** + * Creates connection and logs in + * + * @throws XMPPException + * @throws UnknownHostException + */ + public XmppServerConnection() throws XMPPException, UnknownHostException { + this.dataServerUrl = Config.getDataserverUrl(); + this.user = Config.getXmppUsername(); + this.password = Config.getXmppPassword(); + this.xmppServerAddress = Config.getProp(Config.XMPP_SERVER_KEY, + Config.XMPP_SERVER_DEFAULT); + this.conn = new XMPPConnection(xmppServerAddress); + this.conn.connect(); + this.conn.login(user, password); + log.debug("Connected to XMPP server at address: " + xmppServerAddress); + } + + /* (non-Javadoc) + * @see java.lang.Runnable#run() + */ + @Override + public void run() { + conn.addPacketListener(new PacketListener() { + @Override + public void processPacket(Packet packet) { + log.debug(packet.toXML()); + } + }, new PacketFilter() { + @Override + public boolean accept(Packet packet) { + return true; + } + }); + IQ packet = new IQ() { + @Override + public String getChildElementXML() { + return "" + + "" + + "" + dataServerUrl + ""; + } + }; + packet.setType(Type.SET); + try { + Packet reply = SyncPacketSend.getReply(conn, packet, + PACKET_SEND_TIMEOUT); + log.debug("URL configuration set response: " + reply.toXML()); + } catch (XMPPException e) { + log.warn("Problem sending URL configuration packet", e); + } + while (conn.isConnected()) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + log.warn("Server connection thread interrupted", e); + disconnect(); + } + } + } + + /** + * disconnect from XMPP server + */ + public void disconnect() { + log.debug("Disconnecting from XMPP server"); + conn.disconnect(); + } + +} diff --git a/javaUtilities/collaboration.dataserver/start.sh b/javaUtilities/collaboration.dataserver/start.sh new file mode 100755 index 0000000000..651690b6e1 --- /dev/null +++ b/javaUtilities/collaboration.dataserver/start.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +(cd $(dirname "$0") +PIDFILE=collabserver.pid +if [[ -e $PIDFILE ]] +then + echo "PID file already exists at $PIDFILE, exiting" + exit 1 +fi +nohup java -server -jar collabserver.jar & +echo $! > $PIDFILE +) diff --git a/javaUtilities/collaboration.dataserver/stop.sh b/javaUtilities/collaboration.dataserver/stop.sh new file mode 100755 index 0000000000..2d6a071f8f --- /dev/null +++ b/javaUtilities/collaboration.dataserver/stop.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +(cd $(dirname "$0") +PIDFILE=collabserver.pid +if [[ -e $PIDFILE ]] +then + kill `cat $PIDFILE` + rm $PIDFILE +fi +) diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/META-INF/MANIFEST.MF b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/META-INF/MANIFEST.MF index 3e2051c613..fe75e4a140 100644 --- a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/META-INF/MANIFEST.MF +++ b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/META-INF/MANIFEST.MF @@ -2,10 +2,9 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: CollaborationConfiguration Bundle-SymbolicName: com.raytheon.openfire.plugin.configuration.collaboration;singleton:=true -Bundle-Version: 1.0.0.qualifier +Bundle-Version: 1.14.0 Bundle-Vendor: RAYTHEON Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Require-Bundle: org.jivesoftware.openfire;bundle-version="3.7.1", - org.apache.commons.configuration;bundle-version="1.6.0", org.apache.commons.collections;bundle-version="3.2.0", org.apache.http;bundle-version="4.1.2" diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/HttpConfigurationPlugin.java b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/HttpConfigurationPlugin.java new file mode 100644 index 0000000000..d0cfb45f93 --- /dev/null +++ b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/HttpConfigurationPlugin.java @@ -0,0 +1,259 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.openfire.plugin.configuration.collaboration; + +import java.io.File; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.jivesoftware.openfire.IQRouter; +import org.jivesoftware.openfire.XMPPServer; +import org.jivesoftware.openfire.container.Plugin; +import org.jivesoftware.openfire.container.PluginManager; +import org.jivesoftware.openfire.disco.IQDiscoInfoHandler; +import org.jivesoftware.openfire.event.SessionEventDispatcher; +import org.jivesoftware.util.JiveGlobals; +import org.jivesoftware.util.TaskEngine; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xmpp.packet.JID; + +import com.raytheon.openfire.plugin.configuration.collaboration.configuration.ConfigurationPacket; +import com.raytheon.openfire.plugin.configuration.collaboration.http.HttpStatusMonitor; +import com.raytheon.openfire.plugin.configuration.collaboration.iq.AbstractConfigHandler; +import com.raytheon.openfire.plugin.configuration.collaboration.iq.DataAuthHandler; +import com.raytheon.openfire.plugin.configuration.collaboration.iq.HttpAddressHandler; +import com.raytheon.openfire.plugin.configuration.collaboration.listener.CollaborationSessionEventListener; + +/** + * The main plugin class for the AWIPS II Collaboration HTTP Configuration + * plugin; creates and configures an openfire listener and the http monitor. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Aug 07, 2012            bkowal      Initial creation
+ * Jan 06, 2013  2563      bclement    replaced TaskEngine shutdown with cancel task
+ *                                     added legacy format setter/accessor
+ * Feb 14, 2013 2756       bclement    rename and refactor for operation with generic http
+ *                                     server configured over XMPP
+ * 
+ * 
+ * + * @author bkowal + * @version 1.0 + */ +public class HttpConfigurationPlugin implements Plugin { + private static final Logger logger = LoggerFactory + .getLogger(HttpConfigurationPlugin.class); + + private static final String INTERVAL = "plugin.collaboration.http.interval"; + + private static final long DEFAULT_INTERVAL_MS = 60000; + + private static final long MONITOR_DELAY_MS = 10000; /* 10 seconds */ + + private TaskEngine monitorTaskEngine; + + private CollaborationSessionEventListener listener; + + private HttpStatusMonitor httpStatusMonitor; + + /** + * + */ + public HttpConfigurationPlugin() { + } + + /* + * (non-Javadoc) + * + * @see org.jivesoftware.openfire.container.Plugin#destroyPlugin() + */ + @Override + public void destroyPlugin() { + if ((this.listener == null) == false) { + SessionEventDispatcher.removeListener(this.listener); + + this.listener.dispose(); + this.listener = null; + } + + if ((this.monitorTaskEngine == null) == false) { + // we don't want to shutdown the engine since it is a singleton + // if we do, we can't reload the plugin + this.monitorTaskEngine + .cancelScheduledTask(this.httpStatusMonitor); + this.monitorTaskEngine = null; + } + } + + /** + * Registers IQ configuration handlers with IQ router and adds features to + * info discovery + * + * @param server + * @param handlers + */ + private void registerConfigHandlers(XMPPServer server, + List handlers) { + IQRouter router = server.getIQRouter(); + IQDiscoInfoHandler infoHandler = server.getIQDiscoInfoHandler(); + for (AbstractConfigHandler handler : handlers) { + Iterator iter = handler.getFeatures(); + while (iter.hasNext()) { + infoHandler.addServerFeature(iter.next()); + } + router.addHandler(handler); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.jivesoftware.openfire.container.Plugin#initializePlugin(org.jivesoftware + * .openfire.container.PluginManager, java.io.File) + */ + @Override + public void initializePlugin(PluginManager manager, File arg1) { + XMPPServer server = XMPPServer.getInstance(); + + DataAuthHandler authHandler = new DataAuthHandler(); + HttpAddressHandler addressHandler = new HttpAddressHandler(); + registerConfigHandlers(server, + Arrays.asList(authHandler, addressHandler)); + + /* Retrieve openfire components. */ + JID serverId = new JID(server.getServerInfo().getXMPPDomain()); + + /* The http status monitor */ + this.httpStatusMonitor = new HttpStatusMonitor(addressHandler, serverId); + + /* Create a new listener. */ + this.listener = new CollaborationSessionEventListener(); + + /* Initialize the listener. */ + this.listener + .setHttpStatusChecker(this.httpStatusMonitor); + this.listener.setServerAddress(serverId); + this.listener.setRouter(server.getMessageRouter()); + + /* Make it possible for the listener to receive events. */ + SessionEventDispatcher.addListener(this.listener); + this.scheduleStatusMonitor(); + } + + /** + * Schedules the http collaboration status monitor at the specified, + * configurable interval using the openfire TaskEngine; see + * {@link TaskEngine} + */ + private synchronized void scheduleStatusMonitor() { + logger.info("Scheduling the httpd collaboration status monitor ..."); + if (this.monitorTaskEngine == null) { + this.monitorTaskEngine = TaskEngine.getInstance(); + } + this.monitorTaskEngine.schedule(this.httpStatusMonitor, + MONITOR_DELAY_MS, this.getHttpMonitorInterval()); + } + + /** + * Stops the scheduled http collaboration status monitor if it has been + * scheduled. + */ + private synchronized void stopStatusMonitor() { + if (this.monitorTaskEngine == null) { + return; + } + this.monitorTaskEngine + .cancelScheduledTask(this.httpStatusMonitor); + } + + /** + * Sets the configurable interval for the amount of time between executions + * of the http collaboration status monitor + * + * @param _interval + * the interval in milliseconds + */ + public void setHttpMonitorInterval(long _interval) { + long originalInterval = this.getHttpMonitorInterval(); + if (_interval == originalInterval) { + return; + } + JiveGlobals.setProperty(INTERVAL, Long.toString(_interval)); + this.stopStatusMonitor(); + this.scheduleStatusMonitor(); + } + + /** + * Returns the interval from the openfire configuration + * + * @return the interval in milliseconds + */ + public long getHttpMonitorInterval() { + return JiveGlobals.getLongProperty(INTERVAL, DEFAULT_INTERVAL_MS); + } + + + /** + * Sets the global value for toggling pre 14.3 message format support + * + * @param legacy + */ + public void setLegacySupport(boolean legacy) { + JiveGlobals.setProperty(ConfigurationPacket.LEGACY_KEY, + Boolean.toString(legacy)); + } + + /** + * @return true if configured to support pre 14.3 message format + */ + public boolean hasLegacySupport() { + return JiveGlobals.getBooleanProperty(ConfigurationPacket.LEGACY_KEY, + true); + } + + /** + * Set white list of accounts that belong to dataservers. The first server + * in the list is treated as the primary dataserver. + * + * @param whiteList + */ + public void setDataserverUsers(String whiteList) { + JiveGlobals + .setProperty(AbstractConfigHandler.DATASERVER_USERS_KEY, whiteList); + } + + /** + * @return white list of accounts that belong to dataservers. The first + * server in the list is treated as the primary dataserver. + */ + public String getDataserverUsers() { + return JiveGlobals + .getProperty(AbstractConfigHandler.DATASERVER_USERS_KEY, ""); + } + +} \ No newline at end of file diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/HttpdCollaborationConfigurationPlugin.java b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/HttpdCollaborationConfigurationPlugin.java deleted file mode 100644 index ce68a73d10..0000000000 --- a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/HttpdCollaborationConfigurationPlugin.java +++ /dev/null @@ -1,278 +0,0 @@ -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ -package com.raytheon.openfire.plugin.configuration.collaboration; - -import java.io.File; -import java.net.InetAddress; -import java.net.UnknownHostException; - -import org.apache.commons.configuration.ConfigurationException; -import org.jivesoftware.openfire.MessageRouter; -import org.jivesoftware.openfire.XMPPServer; -import org.jivesoftware.openfire.container.Plugin; -import org.jivesoftware.openfire.container.PluginManager; -import org.jivesoftware.openfire.event.SessionEventDispatcher; -import org.jivesoftware.util.JiveGlobals; -import org.jivesoftware.util.TaskEngine; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xmpp.packet.JID; - -import com.raytheon.openfire.plugin.configuration.collaboration.configuration.ConfigurationPacket; -import com.raytheon.openfire.plugin.configuration.collaboration.configuration.HttpdCollaborationConfiguration; -import com.raytheon.openfire.plugin.configuration.collaboration.httpd.HttpdCollaborationConfReader; -import com.raytheon.openfire.plugin.configuration.collaboration.httpd.HttpdCollaborationStatusMonitor; -import com.raytheon.openfire.plugin.configuration.collaboration.listener.HttpdCollaborationSessionEventListener; - -/** - * The main plugin class for the AWIPS II Httpd Collaboration Configuration - * plugin; creates and configures an openfire listener and the httpd monitor. - * - *
- * 
- * SOFTWARE HISTORY
- * 
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * Aug 07, 2012            bkowal      Initial creation
- * Jan 06, 2013  2563      bclement    replaced TaskEngine shutdown with cancel task
- *                                     added legacy format setter/accessor
- * 
- * 
- * - * @author bkowal - * @version 1.0 - */ -public class HttpdCollaborationConfigurationPlugin implements Plugin { - private static final Logger logger = LoggerFactory - .getLogger(HttpdCollaborationConfigurationPlugin.class); - - private static final String LOCATION = "plugin.collaboration.httpd.location"; - - private static final String INTERVAL = "plugin.collaboration.httpd.interval"; - - private static final String DEFAULT_LOCATION = "/awips2/httpd_collaboration"; - - private static final long DEFAULT_INTERVAL_MS = 60000; - - private static final long MONITOR_DELAY_MS = 60000; /* 1 Minute */ - - private static final String ABORT_ERROR_MESSAGE = "Aborting initialization of the HttpdCollaborationConfigurationPlugin plugin."; - - private HttpdCollaborationSessionEventListener listener; - - private HttpdCollaborationStatusMonitor httpdCollaborationStatusMonitor; - - private TaskEngine monitorTaskEngine; - - /** - * - */ - public HttpdCollaborationConfigurationPlugin() { - } - - /* - * (non-Javadoc) - * - * @see org.jivesoftware.openfire.container.Plugin#destroyPlugin() - */ - @Override - public void destroyPlugin() { - if ((this.listener == null) == false) { - SessionEventDispatcher.removeListener(this.listener); - - this.listener.dispose(); - this.listener = null; - } - - if ((this.monitorTaskEngine == null) == false) { - // we don't want to shutdown the engine since it is a singleton - // if we do, we can't reload the plugin - this.monitorTaskEngine - .cancelScheduledTask(this.httpdCollaborationStatusMonitor); - this.monitorTaskEngine = null; - } - } - - /* - * (non-Javadoc) - * - * @see - * org.jivesoftware.openfire.container.Plugin#initializePlugin(org.jivesoftware - * .openfire.container.PluginManager, java.io.File) - */ - @Override - public void initializePlugin(PluginManager arg0, File arg1) { - /* - * Attempt to read the httpd collaboration configuration. - */ - HttpdCollaborationConfReader confReader = new HttpdCollaborationConfReader( - this.getHttpdCollaborationLocation()); - try { - confReader.execute(); - } catch (ConfigurationException e1) { - logger.error("Unable to read the httpd collaboration configuration.", - e1); - logger.error(ABORT_ERROR_MESSAGE); - return; - } catch (Exception e2) { - logger.error("An unexpected error has occurred.", e2); - logger.error(ABORT_ERROR_MESSAGE); - return; - } - - /* - * Determine the hostname - there is a requirement in place that - * requires openfire and httpd-collaboration to be installed on the same - * machine. - */ - InetAddress address = null; - try { - address = InetAddress.getLocalHost(); - } catch (UnknownHostException e1) { - logger.error("Unable to retrieve the hostname.", e1); - logger.error(ABORT_ERROR_MESSAGE); - return; - } - - /* Persist the configuration information. */ - HttpdCollaborationConfiguration httpdCollaborationConfiguration = new HttpdCollaborationConfiguration(); - httpdCollaborationConfiguration.setSessionDataHost(address - .getHostName()); - httpdCollaborationConfiguration.setSessionDataPort(confReader - .getListenPort()); - - /* The httpd-collaboration status monitor */ - this.httpdCollaborationStatusMonitor = new HttpdCollaborationStatusMonitor( - this.getHttpdCollaborationLocation(), - httpdCollaborationConfiguration.getHttpdCollaborationURL(), - httpdCollaborationConfiguration.toString()); - - /* Retrieve openfire components. */ - JID serverAddress = new JID(XMPPServer.getInstance().getServerInfo() - .getXMPPDomain()); - MessageRouter router = XMPPServer.getInstance().getMessageRouter(); - - /* Create a new listener. */ - this.listener = new HttpdCollaborationSessionEventListener( - httpdCollaborationConfiguration.toString()); - - /* Initialize the listener. */ - this.listener - .setHttpdCollaborationStatusChecker(this.httpdCollaborationStatusMonitor); - this.listener.setServerAddress(serverAddress); - this.listener.setRouter(router); - - /* Make it possible for the listener to receive events. */ - SessionEventDispatcher.addListener(this.listener); - this.scheduleStatusMonitor(); - } - - /** - * Schedules the httpd collaboration status monitor at the specified, - * configurable interval using the openfire TaskEngine; see - * {@link TaskEngine} - */ - private synchronized void scheduleStatusMonitor() { - logger.info("Scheduling the httpd collaboration status monitor ..."); - if (this.monitorTaskEngine == null) { - this.monitorTaskEngine = TaskEngine.getInstance(); - } - this.monitorTaskEngine.schedule(this.httpdCollaborationStatusMonitor, - MONITOR_DELAY_MS, this.getHttpdMonitorInterval()); - } - - /** - * Stops the scheduled httpd collaboration status monitor if it has been - * scheduled. - */ - private synchronized void stopStatusMonitor() { - if (this.monitorTaskEngine == null) { - return; - } - this.monitorTaskEngine - .cancelScheduledTask(this.httpdCollaborationStatusMonitor); - } - - /** - * Sets the configurable installation location of awips2-httpd-collaboration - * - * @param _location - * the location of awips2-httpd-collaboration - */ - public void setHttpdCollaborationLocation(String _location) { - JiveGlobals.setProperty(LOCATION, _location); - } - - /** - * Returns the installation location of awips2-httpd-collaboration from the - * openfire configuration - * - * @return the installation root of awips2-httpd-collaboration - */ - public String getHttpdCollaborationLocation() { - return JiveGlobals.getProperty(LOCATION, DEFAULT_LOCATION); - } - - /** - * Sets the configurable interval for the amount of time between executions - * of the httpd collaboration status monitor - * - * @param _interval - * the interval in milliseconds - */ - public void setHttpdMonitorInterval(long _interval) { - long originalInterval = this.getHttpdMonitorInterval(); - if (_interval == originalInterval) { - return; - } - JiveGlobals.setProperty(INTERVAL, Long.toString(_interval)); - this.stopStatusMonitor(); - this.scheduleStatusMonitor(); - } - - /** - * Returns the interval from the openfire configuration - * - * @return the interval in milliseconds - */ - public long getHttpdMonitorInterval() { - return JiveGlobals.getLongProperty(INTERVAL, DEFAULT_INTERVAL_MS); - } - - /** - * Sets the global value for toggling pre 14.3 message format support - * - * @param legacy - */ - public void setLegacySupport(boolean legacy) { - JiveGlobals.setProperty(ConfigurationPacket.LEGACY_KEY, - Boolean.toString(legacy)); - } - - /** - * @return true if configured to support pre 14.3 message format - */ - public boolean hasLegacySupport() { - return JiveGlobals.getBooleanProperty(ConfigurationPacket.LEGACY_KEY, - true); - } - -} \ No newline at end of file diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/configuration/ConfigurationPacket.java b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/configuration/ConfigurationPacket.java index ca332ecc6c..02ffdc0570 100644 --- a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/configuration/ConfigurationPacket.java +++ b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/configuration/ConfigurationPacket.java @@ -19,11 +19,6 @@ **/ package com.raytheon.openfire.plugin.configuration.collaboration.configuration; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.Properties; - import org.apache.commons.lang.StringUtils; import org.dom4j.Element; import org.jivesoftware.util.JiveGlobals; @@ -32,6 +27,7 @@ import org.slf4j.LoggerFactory; import org.xmpp.packet.Message; import org.xmpp.packet.PacketExtension; + /** * Packet extension for collaboration configuration messages to clients * @@ -42,6 +38,7 @@ import org.xmpp.packet.PacketExtension; * Date Ticket# Engineer Description * ------------ ---------- ----------- -------------------------- * Dec 20, 2013 bclement Initial creation + * Feb 14, 2014 2756 bclement moved preferences to separate file * * * @@ -54,33 +51,6 @@ public class ConfigurationPacket extends PacketExtension { private static final Logger log = LoggerFactory .getLogger(ConfigurationPacket.class); - // format property file - - public static final String CONFIG_FILE_KEY = "plugin.collaboration.packet.format.file"; - - private static final String DEFAULT_PLUGIN_CONFIG_FILE = "conf" - + File.separator + "configurationPacketFormat.properties"; - - private static final Properties properties = new Properties(); - - static { - String confFile = JiveGlobals.getProperty(CONFIG_FILE_KEY, - DEFAULT_PLUGIN_CONFIG_FILE); - File f = new File(JiveGlobals.getHomeDirectory(), confFile); - if (f.exists()) { - try { - properties.load(new FileInputStream(f)); - } catch (IOException e) { - // defaults will be used - log.error("Problem loading packet format configuration file: " - + f.getAbsolutePath(), e); - } - } else { - log.info("Using default config packet format since there was no format file at " - + f.getAbsolutePath()); - } - } - // property keys public static final String XMLNS_KEY = "plugin.collaboration.packet.xmlns"; @@ -128,11 +98,11 @@ public class ConfigurationPacket extends PacketExtension { * configuration payload for packet * @return */ - private static Element create(String body) { - String element = properties.getProperty(ELEMENT_KEY, ELEMENT_DEFAULT); - String xmlns = properties.getProperty(XMLNS_KEY, XMLNS_DEFAULT); + public static Element create(String body) { + String element = PacketPreferences.get(ELEMENT_KEY, ELEMENT_DEFAULT); + String xmlns = PacketPreferences.get(XMLNS_KEY, XMLNS_DEFAULT); Element rval = docFactory.createElement(element, xmlns); - String attributes = properties.getProperty(ATTRIBUTES_KEY, + String attributes = PacketPreferences.get(ATTRIBUTES_KEY, ATTRIBUTES_DEFAULT); for (String keyval : StringUtils.split(attributes, ',')) { String[] separated = StringUtils.split(keyval, '='); diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/configuration/HttpdCollaborationConfiguration.java b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/configuration/HttpdCollaborationConfiguration.java deleted file mode 100644 index c1da2f4682..0000000000 --- a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/configuration/HttpdCollaborationConfiguration.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ -package com.raytheon.openfire.plugin.configuration.collaboration.configuration; - - -/** - * Used to store and format the information retrieved from the - * httpd-collaboration httpd.conf file that will be returned to the client. - * - *
- * 
- * SOFTWARE HISTORY
- * 
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * Aug 07, 2012            bkowal      Initial creation
- * Jan 06, 2013  2563      bclement    removed config preamble
- * 
- * 
- * - * @author bkowal - * @version 1.0 - */ -public class HttpdCollaborationConfiguration { - private static final String SESSION_DATA_URL_FORMAT_STRING = "http://%s:%s/session_data/"; - - private static final String URL_PARAMETER_NAME = "sessionDataHttpURL"; - - private String sessionDataHost; - - private String sessionDataPort; - - /** - * - */ - public HttpdCollaborationConfiguration() { - this.sessionDataHost = null; - this.sessionDataPort = null; - } - - @Override - public String toString() { - return URL_PARAMETER_NAME + " : " + this.getHttpdCollaborationURL(); - } - - public String getHttpdCollaborationURL() { - return String.format(SESSION_DATA_URL_FORMAT_STRING, - this.sessionDataHost, this.sessionDataPort); - } - - public String getSessionDataHost() { - return sessionDataHost; - } - - public void setSessionDataHost(String sessionDataHost) { - this.sessionDataHost = sessionDataHost; - } - - public String getSessionDataPort() { - return sessionDataPort; - } - - public void setSessionDataPort(String sessionDataPort) { - this.sessionDataPort = sessionDataPort; - } -} \ No newline at end of file diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/configuration/PacketPreferences.java b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/configuration/PacketPreferences.java new file mode 100644 index 0000000000..f738b1b6ea --- /dev/null +++ b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/configuration/PacketPreferences.java @@ -0,0 +1,91 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.openfire.plugin.configuration.collaboration.configuration; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; + +import org.jivesoftware.util.JiveGlobals; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Preferences wrapper for packet format + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 10, 2014 2756       bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class PacketPreferences { + + private static final Logger log = LoggerFactory + .getLogger(PacketPreferences.class); + + // format property file + + public static final String CONFIG_FILE_KEY = "plugin.collaboration.packet.format.file"; + + private static final String DEFAULT_PLUGIN_CONFIG_FILE = "conf" + + File.separator + "configurationPacketFormat.properties"; + + private static final Properties properties = new Properties(); + + static { + String confFile = JiveGlobals.getProperty(CONFIG_FILE_KEY, + DEFAULT_PLUGIN_CONFIG_FILE); + File f = new File(JiveGlobals.getHomeDirectory(), confFile); + if (f.exists()) { + try { + properties.load(new FileInputStream(f)); + } catch (IOException e) { + // defaults will be used + log.error("Problem loading packet format configuration file: " + + f.getAbsolutePath(), e); + } + } else { + log.info("Using default config packet format since there was no format file at " + + f.getAbsolutePath()); + } + } + + /** + * Get property from configuration file. Returns defaultValue if key doesn't + * exist + * + * @param key + * @param defaultValue + * @return + */ + public static String get(String key, String defaultValue) { + return properties.getProperty(key, defaultValue); + } + +} diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/exception/HttpdCollaborationNotRunningException.java b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/exception/HttpdCollaborationNotRunningException.java deleted file mode 100644 index f590a498ad..0000000000 --- a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/exception/HttpdCollaborationNotRunningException.java +++ /dev/null @@ -1,73 +0,0 @@ -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ -package com.raytheon.openfire.plugin.configuration.collaboration.exception; - -/** - * Implements an exception that is thrown whenever one of the conditions - * indicating httpd-collaboration is not running occurs. - * - *
- * 
- * SOFTWARE HISTORY
- * 
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * Jul 30, 2012            bkowal     Initial creation
- * 
- * 
- * - * @author bkowal - * @version 1.0 - */ - -public class HttpdCollaborationNotRunningException extends Throwable { - - private static final long serialVersionUID = 6598229436212894638L; - private static final String MESSAGE_PREFIX = "The httpd-collaboration server is not running; "; - - /** - * - */ - public HttpdCollaborationNotRunningException() { - } - - /** - * @param message - */ - public HttpdCollaborationNotRunningException(String message) { - super(MESSAGE_PREFIX + message); - } - - /** - * @param cause - */ - public HttpdCollaborationNotRunningException(Throwable cause) { - super(cause); - } - - /** - * @param message - * @param cause - */ - public HttpdCollaborationNotRunningException(String message, Throwable cause) { - super(MESSAGE_PREFIX + message, cause); - } - -} diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/exception/HttpdCollaborationStatusException.java b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/exception/HttpdCollaborationStatusException.java deleted file mode 100644 index 1e947118d9..0000000000 --- a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/exception/HttpdCollaborationStatusException.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ -package com.raytheon.openfire.plugin.configuration.collaboration.exception; - -/** - * Implements an exception that is thrown whenever it is not possible to - * determine whether or not httpd-collaboration is currently running. - * - *
- *
- * SOFTWARE HISTORY
- *
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * Jul 30, 2012            bkowal     Initial creation
- *
- * 
- * - * @author bkowal - * @version 1.0 - */ - -public class HttpdCollaborationStatusException extends Throwable { - - private static final long serialVersionUID = -2446532142660776343L; - private static final String MESSAGE_PREFIX = "Unable to determine the status of the httpd-collaboration server; "; - - /** - * - */ - public HttpdCollaborationStatusException() { - // TODO Auto-generated constructor stub - } - - /** - * @param message - */ - public HttpdCollaborationStatusException(String message) { - super(MESSAGE_PREFIX + message); - } - - /** - * @param cause - */ - public HttpdCollaborationStatusException(Throwable cause) { - super(cause); - } - - /** - * @param message - * @param cause - */ - public HttpdCollaborationStatusException(String message, Throwable cause) { - super(MESSAGE_PREFIX + message, cause); - } - -} diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/http/HttpStatusMonitor.java b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/http/HttpStatusMonitor.java new file mode 100644 index 0000000000..7aa32622a3 --- /dev/null +++ b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/http/HttpStatusMonitor.java @@ -0,0 +1,259 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.openfire.plugin.configuration.collaboration.http; + +import java.io.IOException; +import java.util.TimerTask; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.http.HttpStatus; +import org.jivesoftware.openfire.SessionManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xmpp.packet.JID; +import org.xmpp.packet.Message; + +import com.raytheon.openfire.plugin.configuration.collaboration.configuration.ConfigurationPacket; +import com.raytheon.openfire.plugin.configuration.collaboration.iq.AbstractConfigHandler; +import com.raytheon.openfire.plugin.configuration.collaboration.iq.HttpAddressHandler; + +/** + * Runs a series of checks to determine if http collaboration is still running + * on-demand and on a scheduled basis. The checks include: verifying that a url + * is configured for the primary dataserver and executing an http GET request + * against the http dataserver. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jul 26, 2012            bkowal      Initial creation
+ * Jan 06, 2013  2563      bclement    replaced chat message with packet extension
+ * Feb 14, 2013 2756       bclement    rename and refactor for operation with generic http
+ *                                     server configured over XMPP
+ * 
+ * 
+ * + * @author bkowal + * @version 1.0 + */ + +public class HttpStatusMonitor extends TimerTask { + private static final Logger logger = LoggerFactory + .getLogger(HttpStatusMonitor.class); + + private final SessionManager sessionManager; + + private static final HttpClient httpClient = new HttpClient(); + + private GetMethod _getMethod = null; + + private String _previousUrl = null; + + private static enum Status { + URL_UNSET, SERVER_DOWN, SERVER_UP + } + + private Status status = Status.URL_UNSET; + + private final HttpAddressHandler addressHandler; + + private final JID serverId; + + /** + * @param addressHandler + * IQ hander responsible for http url configuration + * @param serverId + * id of server used as from address in messages + */ + public HttpStatusMonitor(HttpAddressHandler addressHandler, JID serverId) { + this.sessionManager = SessionManager.getInstance(); + this.addressHandler = addressHandler; + this.serverId = serverId; + } + + /** + * Get the current URL configuration string. + * + * @return null if no valid configuration is available + */ + public String getCurrentUrlConfig() { + String primary = AbstractConfigHandler.getPrimaryDataServer(); + if (primary == null) { + logger.debug("No primary dataserver found"); + urlUnset(); + return null; + } else { + String url = addressHandler.getHttpAddress(primary); + if (url == null) { + logger.debug("No url set for dataserver: " + primary); + urlUnset(); + return null; + } else { + return verifyHttpProcess(url); + } + } + } + + /** + * Verify that the http server is online and accepting requests. Returns the + * valid URL configuration string. + * + * @param url + * url to verify + * @return null if successful request cannot be made + */ + private String verifyHttpProcess(String url) { + synchronized (httpClient) { + int statusCode = -1; + try { + GetMethod get = getCachedMethod(url); + statusCode = httpClient.executeMethod(get); + } catch (HttpException e1) { + String msg = "Unable to execute GET against the collaboration dataserver at " + + url; + logger.error(msg, e1); + setOffline(msg); + } catch (IOException e2) { + String msg = "Unable to read the response from the collaboration dataserver at " + + url; + logger.error(msg, e2); + setOffline(msg); + } + + if ((statusCode == HttpStatus.SC_OK) == false) { + String msg = "Dataserver not is not available - received status " + + statusCode; + logger.error(msg); + setOffline(msg); + return null; + } else { + String urlConfig = "sessionDataHttpURL : " + url; + setOnline(urlConfig); + return urlConfig; + } + } + } + + /** + * Get the http GET method for url. Uses a simple cache. + * + * @param url + * @return + */ + private GetMethod getCachedMethod(String url) { + if (_previousUrl == null || !_previousUrl.equals(url)) { + logger.debug("Dataserver url changed from " + _previousUrl + " to " + + url); + _getMethod = new GetMethod(url); + _previousUrl = url; + } + return _getMethod; + } + + @Override + public void run() { + logger.debug("Verifying that httpd-collaboration is still available ..."); + getCurrentUrlConfig(); + } + + /** + * Broadcast configuration message to all users + * + * @param body + * url or error configuration string + */ + private synchronized void broadcastMessage(String body) { + logger.debug("Broadcasting message: " + body); + Message message = ConfigurationPacket.createMessage(body); + message.setFrom(serverId); + this.sessionManager.broadcast(message); + } + + /** + * Method to call when http server cannot be reached + * + * @param message + */ + private void setOffline(String message) { + switch (status) { + case SERVER_UP: + logger.debug("Status changing from " + status + " to " + + Status.SERVER_DOWN); + broadcastMessage(formatError(message)); + status = Status.SERVER_DOWN; + default: + logger.debug("SetOffline: Status not changed from " + status); + // no action since we don't want to spam with error messages + break; + } + } + + /** + * Format error message to configuration format + * + * @param message + * @return + */ + private String formatError(String message) { + return "error : " + message; + } + + /** + * Method to call when http server is configured and running + * + * @param urlConfig + */ + private void setOnline(String urlConfig) { + switch (status) { + case SERVER_DOWN: + case URL_UNSET: + logger.debug("Status changing from " + status + " to " + + Status.SERVER_UP); + broadcastMessage(urlConfig); + status = Status.SERVER_UP; + break; + default: + logger.debug("SetOnline: Status not changed from " + status); + // no action + } + } + + /** + * Method to call when http server url is not configured + */ + private void urlUnset() { + switch (status) { + case SERVER_UP: + logger.debug("Status changing from " + status + " to " + + Status.URL_UNSET); + broadcastMessage(formatError("Dataserver does not have URL configured in chat server.")); + status = Status.URL_UNSET; + default: + logger.debug("UrlUnset: Status not changed from " + status); + // no action since we don't want to spam with error messages + break; + } + } +} \ No newline at end of file diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/httpd/HttpdCollaborationConfReader.java b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/httpd/HttpdCollaborationConfReader.java deleted file mode 100644 index 7a253b6c7b..0000000000 --- a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/httpd/HttpdCollaborationConfReader.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ -package com.raytheon.openfire.plugin.configuration.collaboration.httpd; - -import org.apache.commons.configuration.ConfigurationException; - -import com.raytheon.openfire.plugin.configuration.collaboration.util.HttpdCollaborationUtil; - -/** - * Reads the httpd.conf file for the configurable httpd-collaboration instance. - * - *
- * 
- * SOFTWARE HISTORY
- * 
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * Aug 7, 2012            bkowal     Initial creation
- * 
- * 
- * - * @author bkowal - * @version 1.0 - */ -public class HttpdCollaborationConfReader { - private static String CONF_FILE; - - private static final String LISTEN_PROPERTY = "Listen"; - - private HttpdCollaborationPropertiesConfiguration propertiesConfiguration; - - /** - * - */ - public HttpdCollaborationConfReader(String _location) { - CONF_FILE = HttpdCollaborationUtil.endPathIfNecessary(_location) - + "etc/httpd/conf/httpd.conf"; - } - - public void execute() throws ConfigurationException { - this.propertiesConfiguration = new HttpdCollaborationPropertiesConfiguration(); - this.propertiesConfiguration.load(CONF_FILE); - } - - public String getListenPort() { - return this.propertiesConfiguration.getString(LISTEN_PROPERTY); - } -} \ No newline at end of file diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/httpd/HttpdCollaborationPropertiesConfiguration.java b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/httpd/HttpdCollaborationPropertiesConfiguration.java deleted file mode 100644 index 23afdecbfe..0000000000 --- a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/httpd/HttpdCollaborationPropertiesConfiguration.java +++ /dev/null @@ -1,84 +0,0 @@ -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ -package com.raytheon.openfire.plugin.configuration.collaboration.httpd; - -import java.io.File; -import java.net.URL; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.PropertiesConfiguration; - -/** - * This class was created because version 1.6 of commons configuration does not - * allow you to decide whether you want to allow includes or not. There is a - * 'setIncludesAllowed' method; however, it is protected. - * - *
- * 
- * SOFTWARE HISTORY
- * 
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------    
- * Aug 2012                bkowal     Initial creation
- * 
- * 
- * - * @author bkowal - * @version 1.0 - */ -public class HttpdCollaborationPropertiesConfiguration extends PropertiesConfiguration { - /** - * - */ - public HttpdCollaborationPropertiesConfiguration() { - super(); - } - - /** - * @param fileName - * @throws ConfigurationException - */ - public HttpdCollaborationPropertiesConfiguration(String fileName) - throws ConfigurationException { - super(fileName); - } - - /** - * @param file - * @throws ConfigurationException - */ - public HttpdCollaborationPropertiesConfiguration(File file) throws ConfigurationException { - super(file); - } - - /** - * @param url - * @throws ConfigurationException - */ - public HttpdCollaborationPropertiesConfiguration(URL url) throws ConfigurationException { - super(url); - } - - @Override - public void setBasePath(String basePath) { - super.setBasePath(basePath); - this.setIncludesAllowed(false); - } -} \ No newline at end of file diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/httpd/HttpdCollaborationStatusMonitor.java b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/httpd/HttpdCollaborationStatusMonitor.java deleted file mode 100644 index 54bd8681ac..0000000000 --- a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/httpd/HttpdCollaborationStatusMonitor.java +++ /dev/null @@ -1,180 +0,0 @@ -/** - * This software was developed and / or modified by Raytheon Company, - * pursuant to Contract DG133W-05-CQ-1067 with the US Government. - * - * U.S. EXPORT CONTROLLED TECHNICAL DATA - * This software product contains export-restricted data whose - * export/transfer/disclosure is restricted by U.S. law. Dissemination - * to non-U.S. persons whether in the United States or abroad requires - * an export license or other authorization. - * - * Contractor Name: Raytheon Company - * Contractor Address: 6825 Pine Street, Suite 340 - * Mail Stop B8 - * Omaha, NE 68106 - * 402.291.0100 - * - * See the AWIPS II Master Rights File ("Master Rights File.pdf") for - * further licensing information. - **/ -package com.raytheon.openfire.plugin.configuration.collaboration.httpd; - -import java.io.File; -import java.io.IOException; -import java.util.TimerTask; - -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpException; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.http.HttpStatus; -import org.jivesoftware.openfire.SessionManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xmpp.packet.Message; - -import com.raytheon.openfire.plugin.configuration.collaboration.configuration.ConfigurationPacket; -import com.raytheon.openfire.plugin.configuration.collaboration.exception.HttpdCollaborationNotRunningException; -import com.raytheon.openfire.plugin.configuration.collaboration.exception.HttpdCollaborationStatusException; -import com.raytheon.openfire.plugin.configuration.collaboration.util.HttpdCollaborationUtil; - -/** - * Runs a series of checks to determine if httpd-collaboration is still running - * on-demand and on a scheduled basis. The checks include: verifying that a pid - * file exists for httpd-collaboration and executing an http GET request against - * the httpd-collaboration server. - * - *
- * 
- * SOFTWARE HISTORY
- * 
- * Date         Ticket#    Engineer    Description
- * ------------ ---------- ----------- --------------------------
- * Jul 26, 2012            bkowal      Initial creation
- * Jan 06, 2013  2563      bclement    replaced chat message with packet extension
- * 
- * 
- * - * @author bkowal - * @version 1.0 - */ - -public class HttpdCollaborationStatusMonitor extends TimerTask { - private static final Logger logger = LoggerFactory - .getLogger(HttpdCollaborationStatusMonitor.class); - - private SessionManager sessionManager; - - private boolean httpdCollaborationBecameUnavailable; - - // provided by the configuration - private String HTTPD_COLLABORATION_CONFIGURATION; - - private static String HTTPD_PID_FILE; - - private static File pidFile; - - private static final HttpClient httpClient = new HttpClient(); - - private GetMethod getMethod; - - /** - * - */ - public HttpdCollaborationStatusMonitor(String _location, - String _httpdCollaborationURL, - String _httpdCollaborationConfiguration) { - HTTPD_PID_FILE = HttpdCollaborationUtil.endPathIfNecessary(_location) - + "var/run/httpd.pid"; - HTTPD_COLLABORATION_CONFIGURATION = _httpdCollaborationConfiguration; - this.sessionManager = SessionManager.getInstance(); - this.httpdCollaborationBecameUnavailable = false; - - pidFile = new File(HTTPD_PID_FILE); - this.getMethod = new GetMethod( - HttpdCollaborationUtil - .endPathIfNecessary(_httpdCollaborationURL)); - } - - public void statusHttpdCollaboration() - throws HttpdCollaborationNotRunningException, - HttpdCollaborationStatusException { - this.doesPidFileExist(); - - // "ping" the httpd process to ensure that it is actually running - this.verifyHttpdProcess(); - } - - private void doesPidFileExist() - throws HttpdCollaborationNotRunningException { - // verify the httpd-collaboration pid file exists. - - if (pidFile.exists() == false) { - // httpd-collaboration is not running - throw new HttpdCollaborationNotRunningException( - "the httpd-collaboration pid file does not exist: " - + pidFile.getAbsolutePath()); - } - } - - private void verifyHttpdProcess() - throws HttpdCollaborationNotRunningException, - HttpdCollaborationStatusException { - synchronized (this.getMethod) { - int statusCode = -1; - try { - statusCode = httpClient.executeMethod(getMethod); - } catch (HttpException e1) { - throw new HttpdCollaborationStatusException( - "Unable to execute GET against the httpd-collaboration server", - e1); - } catch (IOException e2) { - throw new HttpdCollaborationStatusException( - "Unable to read the response from the httpd-collaboration server", - e2); - } - - if ((statusCode == HttpStatus.SC_OK) == false) { - throw new HttpdCollaborationNotRunningException( - "httpd-collaboration is not available - received status = " - + statusCode); - } - } - } - - @Override - public void run() { - logger.debug("Verifying that httpd-collaboration is still available ..."); - String errorMessage = null; - - try { - this.statusHttpdCollaboration(); - } catch (HttpdCollaborationNotRunningException e1) { - logger.error("httpd-collaboration is not available", e1); - this.httpdCollaborationBecameUnavailable = true; - errorMessage = HttpdCollaborationUtil.encodeErrorMessage(e1); - } catch (HttpdCollaborationStatusException e2) { - logger.error( - "unable to determine if httpd-collaboration is still available!!!", - e2); - this.httpdCollaborationBecameUnavailable = true; - errorMessage = HttpdCollaborationUtil.encodeErrorMessage(e2); - } - - if (errorMessage == null && this.httpdCollaborationBecameUnavailable) { - // If we reach this point, httpd-collaboration became - // unavailable at some point in time; re-enable shared displays - // in CAVE for all users. - this.broadcastMessage(HTTPD_COLLABORATION_CONFIGURATION); - this.httpdCollaborationBecameUnavailable = false; - } else { - // Broadcast to all users that httpd-collaboration is no longer - // available; shared displays in CAVE will be disabled - this.broadcastMessage(errorMessage); - } - } - - private synchronized void broadcastMessage(String body) { - Message message = ConfigurationPacket.createMessage(body); - this.sessionManager.broadcast(message); - } -} \ No newline at end of file diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/iq/AbstractConfigHandler.java b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/iq/AbstractConfigHandler.java new file mode 100644 index 0000000000..447ba60350 --- /dev/null +++ b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/iq/AbstractConfigHandler.java @@ -0,0 +1,301 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.openfire.plugin.configuration.collaboration.iq; + +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.dom4j.Element; +import org.dom4j.Namespace; +import org.dom4j.tree.DefaultElement; +import org.jivesoftware.openfire.IQHandlerInfo; +import org.jivesoftware.openfire.PrivateStorage; +import org.jivesoftware.openfire.XMPPServer; +import org.jivesoftware.openfire.auth.UnauthorizedException; +import org.jivesoftware.openfire.disco.ServerFeaturesProvider; +import org.jivesoftware.openfire.handler.IQHandler; +import org.jivesoftware.util.JiveGlobals; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xmpp.packet.IQ; +import org.xmpp.packet.IQ.Type; +import org.xmpp.packet.JID; +import org.xmpp.packet.PacketError; +import org.xmpp.packet.PacketError.Condition; + +/** + * Base IQ handler for configuration over XMPP + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 12, 2014 2756       bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public abstract class AbstractConfigHandler extends IQHandler implements + ServerFeaturesProvider { + + public static final String DATASERVER_USERS_KEY = "plugin.collaboration.dataserver.users"; + + public static final String QUERY_ELEMENT_NAME = "query"; + + public static final String COLLAB_XMLNS = "urn:uf:viz:collaboration"; + + private static final Logger log = LoggerFactory + .getLogger(AbstractConfigHandler.class); + + protected final IQHandlerInfo info; + + protected final List features; + + protected final PrivateStorage storage; + + + /** + * @param moduleName + * display name for handler + * @param features + * xmlns strings for features + * @param info + * qualified name registration information + */ + public AbstractConfigHandler(String moduleName, List features, + IQHandlerInfo info) { + super(moduleName); + this.info = info; + this.features = features; + this.storage = XMPPServer.getInstance().getPrivateStorage(); + } + + /* (non-Javadoc) + * @see org.jivesoftware.openfire.handler.IQHandler#getInfo() + */ + @Override + public IQHandlerInfo getInfo() { + return info; + } + + /* + * (non-Javadoc) + * + * @see + * org.jivesoftware.openfire.handler.IQHandler#handleIQ(org.xmpp.packet.IQ) + */ + @Override + public IQ handleIQ(IQ packet) throws UnauthorizedException { + Type type = packet.getType(); + IQ rval; + switch (type) { + case get: + rval = handleGet(packet); + break; + case set: + rval = handleSet(packet); + break; + default: + rval = createError(packet, new PacketError(Condition.bad_request)); + } + return rval; + } + + /** + * Process get request + * + * @param packet + * request packet + * @return + * @throws UnauthorizedException + */ + abstract protected IQ handleGet(IQ packet) throws UnauthorizedException; + + /** + * Process set request + * + * @param packet + * request packet + * @return + * @throws UnauthorizedException + */ + abstract protected IQ handleSet(IQ packet) throws UnauthorizedException; + + /* + * (non-Javadoc) + * + * @see org.jivesoftware.openfire.disco.ServerFeaturesProvider#getFeatures() + */ + @Override + public Iterator getFeatures() { + return features.iterator(); + } + + /** + * Create error response packet + * + * @param request + * @param error + * @return + */ + protected static IQ createError(IQ request, PacketError error) { + Element child = request.getChildElement(); + child.setParent(null); + IQ rval = IQ.createResultIQ(request); + rval.setType(Type.error); + rval.setChildElement(child); + rval.setError(error); + return rval; + } + + /** + * Get first child of parent found with qualified name + * + * @param parent + * @param name + * @param namespace + * @return + * @throws Exception + * if no child can be found + */ + @SuppressWarnings("unchecked") + protected static Element getChildElement(Element parent, String name, + String namespace) throws Exception { + Element rval = null; + Iterator iter = parent.elementIterator(); + while (iter.hasNext()) { + Element child = iter.next(); + if (child != null && child.getName().equals(name) + && child.getNamespace().getURI().equals(namespace)) { + rval = child; + break; + } + } + if (rval == null) { + log.debug("Missing Data Element: " + parent.asXML()); + String msg = "Missing Required Child Element: " + namespace + " " + + name; + throw new Exception(msg); + } + return rval; + } + + /** + * Remove all child elements from e + * + * @param e + */ + @SuppressWarnings("unchecked") + protected static void removeChildren(Element e) { + Iterator iter = e.elementIterator(); + while (iter.hasNext()) { + e.remove(iter.next()); + } + } + + /** + * @param id + * @return true if id is in the list of dataserver users + */ + protected static boolean isDataServerUser(JID id) { + String usersStr = JiveGlobals.getProperty(DATASERVER_USERS_KEY, ""); + // this will work if the dataserver user is set to a single account or a + // comma separated list or is blank + for (String user : StringUtils.split(usersStr, ',')) { + if (StringUtils.isBlank(user)) { + continue; + } + user = user.trim(); + if (id.toBareJID().equals(user)) { + return true; + } + } + return false; + } + + /** + * Return the primary dataserver which is the first item in the list of + * dataserver users + * + * @return null if none found + */ + public static String getPrimaryDataServer() { + String usersStr = JiveGlobals.getProperty(DATASERVER_USERS_KEY, ""); + String[] users = StringUtils.split(usersStr, ','); + if (users.length < 1) { + return null; + } + // primary server is the only one or first in list + return users[0]; + } + + /** + * Retrieve data from private storage + * + * @param requestPacket + * request IQ for data + * @param id + * user id that data is stored under + * @param key + * empty xml element with qualified name + * @return + */ + protected IQ retrieve(IQ requestPacket, String id, Element key) { + Element queryElem = requestPacket.getChildElement(); + Element respElem = storage.get(id, key); + IQ rval = IQ.createResultIQ(requestPacket); + queryElem.setParent(null); + removeChildren(queryElem); + queryElem.add(respElem); + rval.setChildElement(queryElem); + return rval; + } + + /** + * Store to private data. NOTE: only child XML elements of the root data + * element will be retrievable. No attributes in the root element will be + * retrievable. + * + * @param id + * user id to store data under + * @param data + * xml element with data + */ + protected void store(String id, Element data) { + storage.add(id, data); + } + + /** + * Create empty xml element using qualified name + * + * @param name + * @param namespace + * @return + */ + protected static Element createElement(String name, String namespace) { + return new DefaultElement(name, new Namespace(null, namespace)); + } + +} diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/iq/DataAuthHandler.java b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/iq/DataAuthHandler.java new file mode 100644 index 0000000000..8b39394a7d --- /dev/null +++ b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/iq/DataAuthHandler.java @@ -0,0 +1,184 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.openfire.plugin.configuration.collaboration.iq; + +import java.util.Arrays; + +import org.apache.commons.lang.StringUtils; +import org.dom4j.Element; +import org.jivesoftware.openfire.IQHandlerInfo; +import org.jivesoftware.openfire.XMPPServer; +import org.jivesoftware.openfire.auth.UnauthorizedException; +import org.jivesoftware.openfire.pubsub.Node; +import org.jivesoftware.openfire.pubsub.PubSubModule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xmpp.packet.IQ; +import org.xmpp.packet.JID; +import org.xmpp.packet.PacketError; +import org.xmpp.packet.PacketError.Condition; + +/** + * IQ handle for dataserver authorization and authentication. Stores client + * public keys and authorizes key use for pubsub nodes. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 10, 2014 2756       bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class DataAuthHandler extends AbstractConfigHandler { + + public static final String AUTH_QUERY_XMLNS = "urn:uf:viz:collaboration:iq:auth"; + + public static final String INFO_ELEMENT_NAME = "authinfo"; + + public static final String PUBKEY_ELEMENT_NAME = "publickey"; + + public static final String ALG_ATTRIBUTE = "algorithm"; + + public static final String JID_ATTRIBUTE = "jid"; + + public static final String SESSIONID_ATTRIBUTE = "sessionid"; + + private static final Logger log = LoggerFactory + .getLogger(DataAuthHandler.class); + + private final PubSubModule pubsub; + + /** + * @param moduleName + */ + public DataAuthHandler() { + super("Collaboration Auth Query Handler", Arrays + .asList(AUTH_QUERY_XMLNS), new IQHandlerInfo( + QUERY_ELEMENT_NAME, AUTH_QUERY_XMLNS)); + this.pubsub = XMPPServer.getInstance().getPubSubModule(); + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.openfire.plugin.configuration.collaboration.iq. + * AbstractConfigHandler#handleGet(org.xmpp.packet.IQ) + */ + @Override + protected IQ handleGet(IQ packet) throws UnauthorizedException { + JID from = packet.getFrom(); + String fromBare = from.toBareJID(); + Element queryElem = packet.getChildElement(); + String jid = queryElem.attributeValue(JID_ATTRIBUTE); + if (jid != null) { + if (!jid.equals(fromBare) && !isDataServerUser(from)) { + log.debug("User not authorized: " + from.toFullJID()); + throw new UnauthorizedException( + "User not authorized for service: " + + from.toFullJID()); + } + } else { + jid = fromBare; + } + JID target = new JID(jid); + String sessionId = queryElem.attributeValue(SESSIONID_ATTRIBUTE); + if (StringUtils.isBlank(sessionId)) { + String msg = "Missing attribute: " + SESSIONID_ATTRIBUTE; + log.debug(msg); + return createError(packet, new PacketError(Condition.bad_request, + PacketError.Type.modify, msg)); + } + Node node = pubsub.getNode(sessionId); + if (node == null) { + String msg = "No topic found for session: " + sessionId; + log.debug(msg); + return createError(packet, new PacketError(Condition.not_allowed, + PacketError.Type.cancel, msg)); + } + if (!isOwner(jid, node)){ + String msg = "User '" + jid + "' is not an owner of session '" + + sessionId + "'"; + log.debug(msg); + return createError(packet, new PacketError(Condition.not_allowed, + PacketError.Type.cancel, msg)); + } + return retrieve(packet, target.getNode(), + createElement(INFO_ELEMENT_NAME, COLLAB_XMLNS)); + } + + + /** + * @param jid + * @param node + * @return true if user with jid is owner of node + */ + private boolean isOwner(String jid, Node node) { + for (JID owner : node.getOwners()) { + if (jid.equals(owner.toBareJID())) { + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see com.raytheon.openfire.plugin.configuration.collaboration.iq. + * AbstractConfigHandler#handleSet(org.xmpp.packet.IQ) + */ + @Override + protected IQ handleSet(IQ packet) { + Element queryElem = packet.getChildElement(); + Element infoElem; + Element pubkeyElem; + try { + infoElem = getChildElement(queryElem, INFO_ELEMENT_NAME, + COLLAB_XMLNS); + pubkeyElem = getChildElement(infoElem, PUBKEY_ELEMENT_NAME, + COLLAB_XMLNS); + } catch (Exception e) { + log.debug("Missing Required Element in packet: " + packet.toXML(), + e); + return createError(packet, new PacketError(Condition.bad_request, + PacketError.Type.modify, e.getLocalizedMessage())); + } + String pubKey = pubkeyElem.getText(); + if (StringUtils.isBlank(pubKey)) { + log.debug("Missing Public Key Text"); + return createError(packet, new PacketError(Condition.bad_request, + PacketError.Type.modify, "Missing Required Text Body")); + } + if (StringUtils.isBlank(pubkeyElem.attributeValue(ALG_ATTRIBUTE))) { + String msg = "Missing attribute: " + ALG_ATTRIBUTE; + return createError(packet, new PacketError(Condition.bad_request, + PacketError.Type.modify, msg)); + } + store(packet.getFrom().getNode(), infoElem); + return IQ.createResultIQ(packet); + } + +} diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/iq/HttpAddressHandler.java b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/iq/HttpAddressHandler.java new file mode 100644 index 0000000000..854ddc50c7 --- /dev/null +++ b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/iq/HttpAddressHandler.java @@ -0,0 +1,177 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.openfire.plugin.configuration.collaboration.iq; + +import java.util.Arrays; + +import org.apache.commons.lang.StringUtils; +import org.dom4j.Element; +import org.jivesoftware.openfire.IQHandlerInfo; +import org.jivesoftware.openfire.auth.UnauthorizedException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xmpp.packet.IQ; +import org.xmpp.packet.JID; +import org.xmpp.packet.PacketError; +import org.xmpp.packet.PacketError.Condition; + + +/** + * IQ handler for dataservers to store URL configuration + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Feb 11, 2014 2756       bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public class HttpAddressHandler extends AbstractConfigHandler { + + private static final Logger log = LoggerFactory + .getLogger(HttpAddressHandler.class); + + public static final String HTTP_QUERY_XMLNS = "urn:uf:viz:collaboration:iq:http"; + + public static final String HTTP_ELEMENT_NAME = "httpinfo"; + + public static final String URL_ELEMENT_NAME = "url"; + + public HttpAddressHandler() { + super("Collaboration Dataserver HTTP Address Handler", Arrays + .asList(HTTP_QUERY_XMLNS), new IQHandlerInfo( + QUERY_ELEMENT_NAME, HTTP_QUERY_XMLNS)); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.openfire.plugin.configuration.collaboration.AbstractHandler + * #handleGet(org.xmpp.packet.IQ) + */ + @Override + protected IQ handleGet(IQ packet) throws UnauthorizedException { + String dataserver = getPrimaryDataServer(); + if (dataserver == null) { + // no dataserver configured, return empty response + return IQ.createResultIQ(packet); + } + JID target = new JID(dataserver); + return retrieve(packet, target.getNode(), + createElement(HTTP_ELEMENT_NAME, COLLAB_XMLNS)); + } + + /** + * Set http address for dataserver user with id. + * + * @param id + * @param url + */ + public void setHttpAddress(String id, String url) { + Element httpElem = createElement(HTTP_ELEMENT_NAME, COLLAB_XMLNS); + Element urlElement = createElement(URL_ELEMENT_NAME, COLLAB_XMLNS); + urlElement.setText(url); + urlElement.setParent(null); + httpElem.add(urlElement); + JID target = new JID(id); + store(target.getNode(), httpElem); + } + + /** + * Remove http address for dataserver user with id. + * + * @param id + * @param url + */ + public void removeHttpAddress(String id, String url) { + JID target = new JID(id); + store(target.getNode(), createElement(HTTP_ELEMENT_NAME, COLLAB_XMLNS)); + } + + /** + * Get http address for dataserver user with id. + * + * @param id + * @return + */ + public String getHttpAddress(String id) { + JID target = new JID(id); + Element respElem = storage.get(target.getNode(), + createElement(HTTP_ELEMENT_NAME, COLLAB_XMLNS)); + Element urlElem; + try { + urlElem = getChildElement(respElem, URL_ELEMENT_NAME, COLLAB_XMLNS); + } catch (Exception e) { + // missing url element, no url configured + return null; + } + String rval = urlElem.getText(); + if (StringUtils.isBlank(rval)) { + return null; + } + return rval.trim(); + } + + /* + * (non-Javadoc) + * + * @see + * com.raytheon.openfire.plugin.configuration.collaboration.AbstractHandler + * #handleSet(org.xmpp.packet.IQ) + */ + @Override + protected IQ handleSet(IQ packet) throws UnauthorizedException { + JID from = packet.getFrom(); + if (!isDataServerUser(from)) { + String msg = "User not authorized for service: " + from.toFullJID(); + log.debug(msg); + throw new UnauthorizedException(msg); + } + Element queryElem = packet.getChildElement(); + Element infoElem; + Element urlElem; + try { + infoElem = getChildElement(queryElem, HTTP_ELEMENT_NAME, + COLLAB_XMLNS); + urlElem = getChildElement(infoElem, URL_ELEMENT_NAME, COLLAB_XMLNS); + } catch (Exception e) { + log.debug("Missing Required Element in packet: " + packet.toXML(), + e); + return createError(packet, new PacketError(Condition.bad_request, + PacketError.Type.modify, e.getLocalizedMessage())); + } + String url = urlElem.getText(); + if (StringUtils.isBlank(url)) { + log.debug("Missing HTTP URL Text"); + return createError(packet, new PacketError(Condition.bad_request, + PacketError.Type.modify, "Missing Required Text Body")); + } + store(packet.getFrom().getNode(), infoElem); + return IQ.createResultIQ(packet); + } + +} diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/listener/HttpdCollaborationSessionEventListener.java b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/listener/CollaborationSessionEventListener.java similarity index 69% rename from javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/listener/HttpdCollaborationSessionEventListener.java rename to javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/listener/CollaborationSessionEventListener.java index 5754237409..86da9ff5d1 100644 --- a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/listener/HttpdCollaborationSessionEventListener.java +++ b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/java/com/raytheon/openfire/plugin/configuration/collaboration/listener/CollaborationSessionEventListener.java @@ -25,16 +25,11 @@ import org.jivesoftware.openfire.MessageRouter; import org.jivesoftware.openfire.event.SessionEventListener; import org.jivesoftware.openfire.session.Session; import org.jivesoftware.util.TaskEngine; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.xmpp.packet.JID; import org.xmpp.packet.Message; import com.raytheon.openfire.plugin.configuration.collaboration.configuration.ConfigurationPacket; -import com.raytheon.openfire.plugin.configuration.collaboration.exception.HttpdCollaborationNotRunningException; -import com.raytheon.openfire.plugin.configuration.collaboration.exception.HttpdCollaborationStatusException; -import com.raytheon.openfire.plugin.configuration.collaboration.httpd.HttpdCollaborationStatusMonitor; -import com.raytheon.openfire.plugin.configuration.collaboration.util.HttpdCollaborationUtil; +import com.raytheon.openfire.plugin.configuration.collaboration.http.HttpStatusMonitor; /** * Impelements @{link SessionEventListener} to wait for new users to connect to @@ -48,23 +43,18 @@ import com.raytheon.openfire.plugin.configuration.collaboration.util.HttpdCollab * ------------ ---------- ----------- -------------------------- * Aug 07, 2012 bkowal Initial creation * Jan 06, 2013 2563 bclement replaced chat message with packet extension + * Feb 14, 2013 2756 bclement refactor for operation with generic http dataserver * * * * @author bkowal * @version 1.0 */ -public class HttpdCollaborationSessionEventListener implements - SessionEventListener { - private static final Logger logger = LoggerFactory - .getLogger(HttpdCollaborationSessionEventListener.class); - - // provided by the configuration - private String HTTPD_COLLABORATION_CONFIGURATION; +public class CollaborationSessionEventListener implements SessionEventListener { private static final int MSG_SEND_DELAY = 5000; - private HttpdCollaborationStatusMonitor httpdCollaborationStatusMonitor; + private HttpStatusMonitor statusMonitor; private JID serverAddress; @@ -73,9 +63,7 @@ public class HttpdCollaborationSessionEventListener implements /** * */ - public HttpdCollaborationSessionEventListener( - String _httpdCollaborationConfiguration) { - HTTPD_COLLABORATION_CONFIGURATION = _httpdCollaborationConfiguration; + public CollaborationSessionEventListener() { this.serverAddress = null; this.router = null; } @@ -129,6 +117,10 @@ public class HttpdCollaborationSessionEventListener implements */ @Override public void sessionCreated(Session session) { + String body = this.composeMessageBody(); + if (body == null) { + return; + } final Message message = ConfigurationPacket.createMessage(this .composeMessageBody()); message.setTo(session.getAddress()); @@ -157,27 +149,12 @@ public class HttpdCollaborationSessionEventListener implements private String composeMessageBody() { // Verify that httpd-collaboration is / is still running. - try { - this.httpdCollaborationStatusMonitor.statusHttpdCollaboration(); - } catch (HttpdCollaborationNotRunningException e1) { - logger.error("httpd-collaboration is not running.", e1); - return HttpdCollaborationUtil.encodeErrorMessage(e1); - } catch (HttpdCollaborationStatusException e2) { - logger.error( - "failed to determine the status of httpd-collaboration", e2); - return HttpdCollaborationUtil.encodeErrorMessage(e2); - } catch (Exception e3) { - logger.error("Unexpected exception occurred!", e3); - return HttpdCollaborationUtil.encodeErrorMessage(e3); - } - - return HTTPD_COLLABORATION_CONFIGURATION; + return statusMonitor.getCurrentUrlConfig(); } - public void setHttpdCollaborationStatusChecker( - HttpdCollaborationStatusMonitor httpdCollaborationStatusMonitor) { - this.httpdCollaborationStatusMonitor = httpdCollaborationStatusMonitor; - } + public void setHttpStatusChecker(HttpStatusMonitor httpStatusMonitor) { + this.statusMonitor = httpStatusMonitor; + } /** * @param serverAddress diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/plugin.xml b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/plugin.xml index ed1e35899e..ee9b9ac8d2 100644 --- a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/plugin.xml +++ b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/plugin.xml @@ -1,23 +1,23 @@ - com.raytheon.openfire.plugin.configuration.collaboration.HttpdCollaborationConfigurationPlugin - Httpd Collaboration Configuration + com.raytheon.openfire.plugin.configuration.collaboration.HttpConfigurationPlugin + Http Collaboration Configuration - This plugin will provide httpd collaboration configuration information to CAVE + This plugin will provide http collaboration configuration information to CAVE via openfire whenever a user logs in to openfire. bkowal - 1.0.0 + 2.0.0 8/08/2012 3.7.1 - + diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/setup.xml b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/setup.xml index 6712b0666e..5f82ba2a4e 100644 --- a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/setup.xml +++ b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/setup.xml @@ -15,7 +15,7 @@ extract dependency information from the plugin manifest. --> + value="org.apache.commons.collections,org.apache.http" /> \ No newline at end of file diff --git a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/web/httpd-collaboration-monitor-admin.jsp b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/web/http-collaboration-monitor-admin.jsp similarity index 60% rename from javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/web/httpd-collaboration-monitor-admin.jsp rename to javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/web/http-collaboration-monitor-admin.jsp index 35e81226cc..9ad981c530 100644 --- a/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/web/httpd-collaboration-monitor-admin.jsp +++ b/javaUtilities/com.raytheon.openfire.plugin.configuration.collaboration/web/http-collaboration-monitor-admin.jsp @@ -1,6 +1,6 @@ <%@ page import="org.jivesoftware.openfire.XMPPServer, - com.raytheon.openfire.plugin.configuration.collaboration.HttpdCollaborationConfigurationPlugin, + com.raytheon.openfire.plugin.configuration.collaboration.HttpConfigurationPlugin, org.jivesoftware.util.ParamUtils, java.util.HashMap, java.util.Map" @@ -12,31 +12,33 @@ <% final long DEFAULT_INTERVAL_S = 60; boolean save = ((request.getParameter("save") == null) == false); - - // Currently, users are not allowed to modify the httpd-collaboration location - // because the rpm is not relocatable. long interval = ParamUtils.getLongParameter(request, "txtInterval", DEFAULT_INTERVAL_S); boolean legacy = ParamUtils.getBooleanParameter(request, "chkLegacy", false); + String dataserverUsers = ParamUtils.getParameter(request, "txtdataserverUsers", true); + if (dataserverUsers == null){ + dataserverUsers = ""; + } - HttpdCollaborationConfigurationPlugin plugin = (HttpdCollaborationConfigurationPlugin) XMPPServer.getInstance().getPluginManager().getPlugin("com.raytheon.openfire.plugin.configuration.collaboration"); + HttpConfigurationPlugin plugin = (HttpConfigurationPlugin) XMPPServer.getInstance().getPluginManager().getPlugin("com.raytheon.openfire.plugin.configuration.collaboration"); if (save) { - plugin.setHttpdMonitorInterval(interval * 1000); + plugin.setHttpMonitorInterval(interval * 1000); plugin.setLegacySupport(legacy); - response.sendRedirect("httpd-collaboration-monitor-admin.jsp?settingsSaved=true"); + plugin.setDataserverUsers(dataserverUsers); + response.sendRedirect("http-collaboration-monitor-admin.jsp?settingsSaved=true"); return; } - String location = plugin.getHttpdCollaborationLocation(); - interval = (plugin.getHttpdMonitorInterval() / 1000); + interval = (plugin.getHttpMonitorInterval() / 1000); String legacyChkValue = plugin.hasLegacySupport() ? "checked" : ""; + dataserverUsers = plugin.getDataserverUsers(); %> - Httpd Collaboration Monitor Settings - + Http Collaboration Monitor Settings + -
+
- Httpd Collaboration Monitor Settings + Http Collaboration Monitor Settings
<% if (ParamUtils.getBooleanParameter(request, "settingsSaved")) { %> @@ -97,17 +119,11 @@ <% } %>

- Set how often (in seconds) the Httpd Collaboration Monitor should verify that the httpd-collaboration process is running. + Set how often (in seconds) the Http Collaboration Monitor should verify that the dataserver is online.

- - - -
location:  - <%= location %> -
interval:  @@ -135,6 +151,26 @@
+


+

+ HTTP Dataserver users list. User ids that http servers can use to communication with openfire. Comma separated list of full user ids + the first id in the list will be used as the primary HTTP Dataserver. Only user ids that are in this list will be allowed to query for session public keys. +

+ + + + + + + + +
Dataserver User Ids:  + + +