accntMap = new ConcurrentHashMap<>();
+
+ public SystemRealm(String systemUserName, String systemPassword) throws Exception {
+ if (systemPassword == null || systemPassword.isEmpty()) {
+ throw new Exception("Invalid system password");
+ }
+ if (systemUserName == null || systemUserName.isEmpty()) {
+ throw new Exception("Invalid system username");
+ }
+ SimpleAccount accnt = new SimpleAccount(systemUserName, systemPassword, getName());
+ accnt.addStringPermission("*");
+ accntMap.put("system", accnt);
+ }
+
+ @Override
+ protected AuthorizationInfo doGetAuthorizationInfo(
+ PrincipalCollection principals) {
+ // get the principal this realm cares about:
String username = (String) getAvailablePrincipal(principals);
-
- if (accntMap.containsKey(username)){
- return accntMap.get(username);
+
+ if (accntMap.containsKey(username)) {
+ return accntMap.get(username);
}
-
+
return null;
- }
+ }
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(
- AuthenticationToken token) throws AuthenticationException {
- // we can safely cast to a UsernamePasswordToken here, because this class 'supports' UsernamePasswordToken
- // objects. See the Realm.supports() method if your application will use a different type of token.
+ @Override
+ protected AuthenticationInfo doGetAuthenticationInfo(
+ AuthenticationToken token) throws AuthenticationException {
+ // we can safely cast to a UsernamePasswordToken here, because this class
+ // 'supports' UsernamePasswordToken
+ // objects. See the Realm.supports() method if your application will use a
+ // different type of token.
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
- return accntMap.get(upToken.getUsername());
- }
+ return accntMap.get(upToken.getUsername());
+ }
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/security/ldap/GossLDAPRealm.java b/pnnl.goss.core/src/pnnl/goss/core/security/ldap/GossLDAPRealm.java
index 8a56c04c..729ebac6 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/security/ldap/GossLDAPRealm.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/security/ldap/GossLDAPRealm.java
@@ -1,129 +1,290 @@
package pnnl.goss.core.security.ldap;
-import java.util.Dictionary;
+
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.URI;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
-import org.apache.felix.dm.annotation.api.Component;
-import org.apache.felix.dm.annotation.api.ConfigurationDependency;
-import org.apache.felix.dm.annotation.api.ServiceDependency;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.authz.permission.PermissionResolver;
+import org.apache.shiro.realm.ldap.DefaultLdapRealm;
import org.apache.shiro.realm.ldap.JndiLdapContextFactory;
-import org.apache.shiro.realm.ldap.JndiLdapRealm;
import org.apache.shiro.subject.PrincipalCollection;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Modified;
+import org.osgi.service.component.annotations.Reference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.northconcepts.exception.SystemException;
import pnnl.goss.core.security.GossPermissionResolver;
import pnnl.goss.core.security.GossRealm;
-import com.northconcepts.exception.SystemException;
+/**
+ * LDAP-based authentication realm for GOSS.
+ *
+ * This component only activates when a configuration file exists
+ * (pnnl.goss.core.security.ldap.cfg) with enabled=true and the LDAP server is
+ * reachable.
+ *
+ * Example configuration:
+ *
+ *
+ * enabled=true
+ * ldap.url=ldap://localhost:10389
+ * ldap.userDnTemplate=uid={0},ou=users,ou=goss,ou=system
+ * ldap.systemUsername=uid=admin,ou=system
+ * ldap.systemPassword=secret
+ * ldap.connectionTimeout=5000
+ *
+ */
+@Component(service = GossRealm.class, configurationPid = "pnnl.goss.core.security.ldap", configurationPolicy = ConfigurationPolicy.REQUIRE)
+public class GossLDAPRealm extends DefaultLdapRealm implements GossRealm {
+
+ private static final Logger log = LoggerFactory.getLogger(GossLDAPRealm.class);
+
+ private static final String PROP_ENABLED = "enabled";
+ private static final String PROP_LDAP_URL = "ldap.url";
+ private static final String PROP_USER_DN_TEMPLATE = "ldap.userDnTemplate";
+ private static final String PROP_SYSTEM_USERNAME = "ldap.systemUsername";
+ private static final String PROP_SYSTEM_PASSWORD = "ldap.systemPassword";
+ private static final String PROP_CONNECTION_TIMEOUT = "ldap.connectionTimeout";
+
+ private static final String DEFAULT_USER_DN_TEMPLATE = "uid={0},ou=users,ou=goss,ou=system";
+ private static final int DEFAULT_CONNECTION_TIMEOUT = 5000;
+
+ @Reference
+ private GossPermissionResolver gossPermissionResolver;
+
+ private boolean enabled = false;
+ private String ldapUrl = null;
+
+ public GossLDAPRealm() {
+ // Don't configure in constructor - wait for configuration
+ }
+
+ @Activate
+ public void activate(Map properties) {
+ log.info("Activating GossLDAPRealm");
+ configure(properties);
+ }
+
+ @Deactivate
+ public void deactivate() {
+ log.info("Deactivating GossLDAPRealm");
+ enabled = false;
+ }
+
+ private void configure(Map properties) {
+ if (properties == null) {
+ log.warn("No configuration provided for LDAP realm");
+ enabled = false;
+ return;
+ }
+
+ // Check if enabled
+ String enabledStr = getStringProperty(properties, PROP_ENABLED, "false");
+ if (!"true".equalsIgnoreCase(enabledStr)) {
+ log.info("LDAP realm is disabled by configuration");
+ enabled = false;
+ return;
+ }
+
+ // Get LDAP URL
+ ldapUrl = getStringProperty(properties, PROP_LDAP_URL, null);
+ if (ldapUrl == null || ldapUrl.isEmpty()) {
+ log.warn("LDAP URL not configured - LDAP realm will not be active");
+ enabled = false;
+ return;
+ }
+
+ // Get connection timeout
+ int connectionTimeout = getIntProperty(properties, PROP_CONNECTION_TIMEOUT,
+ DEFAULT_CONNECTION_TIMEOUT);
+
+ // Test connectivity before enabling
+ if (!isLdapServerReachable(ldapUrl, connectionTimeout)) {
+ log.warn("LDAP server at {} is not reachable - LDAP realm will not be active", ldapUrl);
+ enabled = false;
+ return;
+ }
+
+ // Configure the realm
+ String userDnTemplate = getStringProperty(properties, PROP_USER_DN_TEMPLATE,
+ DEFAULT_USER_DN_TEMPLATE);
+ String systemUsername = getStringProperty(properties, PROP_SYSTEM_USERNAME, null);
+ String systemPassword = getStringProperty(properties, PROP_SYSTEM_PASSWORD, null);
+
+ try {
+ setUserDnTemplate(userDnTemplate);
+
+ JndiLdapContextFactory contextFactory = new JndiLdapContextFactory();
+ contextFactory.setUrl(ldapUrl);
+
+ if (systemUsername != null && !systemUsername.isEmpty()) {
+ contextFactory.setSystemUsername(systemUsername);
+ }
+ if (systemPassword != null && !systemPassword.isEmpty()) {
+ contextFactory.setSystemPassword(systemPassword);
+ }
+
+ setContextFactory(contextFactory);
+ enabled = true;
+ log.info("LDAP realm configured: url={}, userDnTemplate={}", ldapUrl, userDnTemplate);
+
+ } catch (Exception e) {
+ log.error("Failed to configure LDAP realm", e);
+ enabled = false;
+ }
+ }
+
+ private boolean isLdapServerReachable(String url, int timeoutMs) {
+ try {
+ URI uri = new URI(url);
+ String host = uri.getHost();
+ int port = uri.getPort();
+
+ if (port == -1) {
+ port = "ldaps".equalsIgnoreCase(uri.getScheme()) ? 636 : 389;
+ }
+
+ log.debug("Testing LDAP connectivity to {}:{}", host, port);
+
+ try (Socket socket = new Socket()) {
+ socket.connect(new InetSocketAddress(host, port), timeoutMs);
+ log.debug("LDAP server {}:{} is reachable", host, port);
+ return true;
+ }
+ } catch (Exception e) {
+ log.debug("LDAP server {} is not reachable: {}", url, e.getMessage());
+ return false;
+ }
+ }
+
+ private String getStringProperty(Map props, String key, String defaultVal) {
+ Object value = props.get(key);
+ if (value instanceof String && !((String) value).isEmpty()) {
+ return (String) value;
+ }
+ return defaultVal;
+ }
+
+ private int getIntProperty(Map props, String key, int defaultVal) {
+ Object value = props.get(key);
+ if (value instanceof Integer) {
+ return (Integer) value;
+ }
+ if (value instanceof String) {
+ try {
+ return Integer.parseInt((String) value);
+ } catch (NumberFormatException e) {
+ // Fall through
+ }
+ }
+ return defaultVal;
+ }
+
+ @Override
+ public Set getPermissions(String identifier) {
+ if (!enabled) {
+ return new HashSet<>();
+ }
+ log.debug("LDAP getPermissions for: {}", identifier);
+ // TODO: Implement LDAP-based permission lookup
+ return new HashSet<>();
+ }
+
+ @Override
+ public boolean hasIdentifier(String identifier) {
+ if (!enabled) {
+ return false;
+ }
+ log.debug("LDAP hasIdentifier: {}", identifier);
+ return false;
+ }
+
+ @Override
+ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+ if (!enabled) {
+ return null;
+ }
+
+ log.debug("LDAP doGetAuthorizationInfo for principals: {}", principals);
+ AuthorizationInfo info = super.doGetAuthorizationInfo(principals);
+
+ if (info == null) {
+ // Provide default permissions for authenticated LDAP users
+ SimpleAuthorizationInfo defaultInfo = new SimpleAuthorizationInfo();
+ defaultInfo.addRole("user");
+ defaultInfo.addStringPermission("queue:*");
+ defaultInfo.addStringPermission("temp-queue:*");
+ defaultInfo.addStringPermission("topic:*");
+ info = defaultInfo;
+ }
+
+ return info;
+ }
+
+ @Override
+ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
+ throws AuthenticationException {
+ if (!enabled) {
+ log.debug("LDAP realm not enabled, skipping authentication");
+ return null;
+ }
+
+ log.debug("LDAP authentication attempt for: {}", token.getPrincipal());
+ try {
+ AuthenticationInfo info = super.doGetAuthenticationInfo(token);
+ if (info != null) {
+ log.info("LDAP authentication successful for: {}", token.getPrincipal());
+ }
+ return info;
+ } catch (AuthenticationException e) {
+ log.debug("LDAP authentication failed for {}: {}", token.getPrincipal(), e.getMessage());
+ throw e;
+ }
+ }
+
+ @Override
+ public boolean supports(AuthenticationToken token) {
+ if (!enabled) {
+ return false;
+ }
+ boolean supports = super.supports(token);
+ log.debug("LDAP supports token {}: {}", token.getClass().getSimpleName(), supports);
+ return supports;
+ }
+
+ @Modified
+ public synchronized void updated(Map properties) throws SystemException {
+ log.info("Updating GossLDAPRealm configuration");
+ configure(properties);
+ }
+
+ @Override
+ public PermissionResolver getPermissionResolver() {
+ if (gossPermissionResolver != null) {
+ return gossPermissionResolver;
+ }
+ return super.getPermissionResolver();
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
-@Component
-public class GossLDAPRealm extends JndiLdapRealm implements GossRealm{
- private static final String CONFIG_PID = "pnnl.goss.core.security.ldap";
-
- @ServiceDependency
- GossPermissionResolver gossPermissionResolver;
-
- public GossLDAPRealm(){
- //TODO move these to config
- setUserDnTemplate("uid={0},ou=users,ou=goss,ou=system");
- JndiLdapContextFactory fac = new JndiLdapContextFactory();
- fac.setUrl("ldap://localhost:10389");
-// fac.setSystemUsername("uid=admin,ou=system");
-// fac.setSystemPassword("SYSTEMPW");
- setContextFactory(fac);
- }
-
- @Override
- public Set getPermissions(String identifier) {
-
- //look up permissions based on roles
-
- return new HashSet();
- }
-
-
- @Override
- public boolean hasIdentifier(String identifier) {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(
- PrincipalCollection principals) {
- // TODO Auto-generated method stub
- AuthorizationInfo info = super.doGetAuthorizationInfo(principals);
-
- if(info==null){
-// try {
- info = new SimpleAuthorizationInfo();
- //at the very least make sure they have the user role and can use the request and advisory topic
- ((SimpleAuthorizationInfo)info).addRole("user");
-
- ((SimpleAuthorizationInfo)info).addStringPermission("queue:*");
- ((SimpleAuthorizationInfo)info).addStringPermission("temp-queue:*");
- ((SimpleAuthorizationInfo)info).addStringPermission("topic:*"); //
-
- //LdapContext ctx = getContextFactory().getSystemLdapContext();
- //TODO lookup roles for user
-
-// } catch (NamingException e) {
-// // TODO Auto-generated catch block
-// e.printStackTrace();
-// }
-
-
- }
-
- return info;
- }
-
- @Override
- public void setUserDnTemplate(String arg0) throws IllegalArgumentException {
- // TODO Auto-generated method stub
- super.setUserDnTemplate(arg0);
- }
-
-
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(
- AuthenticationToken token) throws AuthenticationException {
-
- // TODO Auto-generated method stub
- AuthenticationInfo info = super.doGetAuthenticationInfo(token);
- return info;
- }
-
- @Override
- public boolean supports(AuthenticationToken token) {
- // TODO Auto-generated method stub
- boolean supports = super.supports(token);
- return supports;
- }
-
- @ConfigurationDependency(pid=CONFIG_PID)
- public synchronized void updated(Dictionary properties) throws SystemException {
-
- if (properties != null) {
- //TODO
-// shouldStartBroker = Boolean.parseBoolean(Optional
-// .ofNullable((String) properties.get(PROP_START_BROKER))
-// .orElse("true"));
-
- }
- }
-
- @Override
- public PermissionResolver getPermissionResolver() {
- if(gossPermissionResolver!=null)
- return gossPermissionResolver;
- else
- return super.getPermissionResolver();
- }
-
+ public String getLdapUrl() {
+ return ldapUrl;
+ }
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/security/packageinfo b/pnnl.goss.core/src/pnnl/goss/core/security/packageinfo
index 0e35eb04..e73c5a45 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/security/packageinfo
+++ b/pnnl.goss.core/src/pnnl/goss/core/security/packageinfo
@@ -1 +1 @@
-version 7.0.0
+version 11.0.0
diff --git a/pnnl.goss.core/src/pnnl/goss/core/security/propertyfile/PropertyBasedRealm.java b/pnnl.goss.core/src/pnnl/goss/core/security/propertyfile/PropertyBasedRealm.java
index 144b993e..c353bae8 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/security/propertyfile/PropertyBasedRealm.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/security/propertyfile/PropertyBasedRealm.java
@@ -1,15 +1,10 @@
package pnnl.goss.core.security.propertyfile;
-import java.util.Dictionary;
-import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
-import org.apache.felix.dm.annotation.api.Component;
-import org.apache.felix.dm.annotation.api.ConfigurationDependency;
-import org.apache.felix.dm.annotation.api.ServiceDependency;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
@@ -19,105 +14,131 @@
import org.apache.shiro.authz.permission.PermissionResolver;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.component.annotations.Modified;
+import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.northconcepts.exception.SystemException;
+
import pnnl.goss.core.security.GossPermissionResolver;
import pnnl.goss.core.security.GossRealm;
-import com.northconcepts.exception.SystemException;
-
/**
- * This class handles property based authentication/authorization. It will only be
- * started as a component if a pnnl.goss.core.security.properties.cfg file exists
- * within the configuration directory.
- *
- * The format of each property should be username=password,permission1,permission2 ... where
- * permission1 and permission2 are of the format domain:object:action. There can be multiple
- * levels of domain object and action. An example permission string format is printers:lp2def:create
- * or topic:request:subscribe.
- *
+ * This class handles property based authentication/authorization. It will only
+ * be started as a component if a pnnl.goss.core.security.properties.cfg file
+ * exists within the configuration directory.
+ *
+ * The format of each property should be
+ * username=password,permission1,permission2 ... where permission1 and
+ * permission2 are of the format domain:object:action. There can be multiple
+ * levels of domain object and action. An example permission string format is
+ * printers:lp2def:create or topic:request:subscribe.
+ *
* NOTE: This class assumes uniqueness of username in the properties file.
- *
+ *
* @author Craig Allwardt
*
*/
-@Component
+@Component(service = GossRealm.class, configurationPid = "pnnl.goss.core.security.propertyfile", configurationPolicy = ConfigurationPolicy.REQUIRE)
public class PropertyBasedRealm extends AuthorizingRealm implements GossRealm {
-
- private static final String CONFIG_PID = "pnnl.goss.core.security.propertyfile";
- private static final Logger log = LoggerFactory.getLogger(PropertyBasedRealm.class);
-
- private final Map userMap = new ConcurrentHashMap<>();
- private final Map> userPermissions = new ConcurrentHashMap<>();
-
- @ServiceDependency
- GossPermissionResolver gossPermissionResolver;
-
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(
- PrincipalCollection principals) {
-
- //get the principal this realm cares about:
+
+ private static final Logger log = LoggerFactory.getLogger(PropertyBasedRealm.class);
+
+ private final Map userMap = new ConcurrentHashMap<>();
+ private final Map> userPermissions = new ConcurrentHashMap<>();
+
+ @Reference
+ GossPermissionResolver gossPermissionResolver;
+
+ @Activate
+ public void activate(Map properties) {
+ log.info("Activating PropertyBasedRealm");
+ updated(properties);
+ }
+
+ @Override
+ protected AuthorizationInfo doGetAuthorizationInfo(
+ PrincipalCollection principals) {
+
+ // get the principal this realm cares about:
String username = (String) getAvailablePrincipal(principals);
return userMap.get(username);
- }
-
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(
- AuthenticationToken token) throws AuthenticationException {
-
- //we can safely cast to a UsernamePasswordToken here, because this class 'supports' UsernamePasswordToken
- //objects. See the Realm.supports() method if your application will use a different type of token.
+ }
+
+ @Override
+ protected AuthenticationInfo doGetAuthenticationInfo(
+ AuthenticationToken token) throws AuthenticationException {
+
+ // we can safely cast to a UsernamePasswordToken here, because this class
+ // 'supports' UsernamePasswordToken
+ // objects. See the Realm.supports() method if your application will use a
+ // different type of token.
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
return userMap.get(upToken.getUsername());
- }
-
- @ConfigurationDependency(pid=CONFIG_PID)
- public synchronized void updated(Dictionary properties) throws SystemException {
-
- if (properties != null){
- log.debug("Updating PropertyBasedRealm");
- userMap.clear();
- userPermissions.clear();
-
- Enumeration keys = properties.keys();
- Set perms = new HashSet<>();
- while(keys.hasMoreElements()){
- String k = keys.nextElement();
- String v = (String)properties.get(k);
- String[] credAndPermissions = v.split(",");
-
- SimpleAccount acnt = new SimpleAccount(k, credAndPermissions[0], getName() );
- for(int i =1; i getPermissions(String identifier) {
- if (hasIdentifier(identifier)){
- return userPermissions.get(identifier);
- }
- return new HashSet<>();
- }
-
- @Override
- public boolean hasIdentifier(String identifier) {
- return userMap.containsKey(identifier);
- }
-
- @Override
- public PermissionResolver getPermissionResolver() {
- if(gossPermissionResolver!=null)
- return gossPermissionResolver;
- else
- return super.getPermissionResolver();
- }
+ }
+
+ @Modified
+ public synchronized void updated(Map properties) throws SystemException {
+
+ if (properties != null) {
+ log.debug("Updating PropertyBasedRealm with {} properties", properties.size());
+ userMap.clear();
+ userPermissions.clear();
+
+ for (String k : properties.keySet()) {
+ // Skip OSGi/ConfigAdmin metadata properties
+ if (k.startsWith("service.") || k.startsWith("component.") ||
+ k.startsWith("felix.") || k.equals("osgi.ds.satisfying.condition.target")) {
+ continue;
+ }
+
+ Object value = properties.get(k);
+ // Only process String values (skip Long, Boolean, etc.)
+ if (!(value instanceof String)) {
+ log.debug("Skipping non-string property: {} = {} ({})", k, value,
+ value != null ? value.getClass().getName() : "null");
+ continue;
+ }
+
+ String v = (String) value;
+ String[] credAndPermissions = v.split(",");
+
+ SimpleAccount acnt = new SimpleAccount(k, credAndPermissions[0], getName());
+ Set perms = new HashSet<>();
+ for (int i = 1; i < credAndPermissions.length; i++) {
+ acnt.addStringPermission(credAndPermissions[i]);
+ perms.add(credAndPermissions[i]);
+ }
+ userMap.put(k, acnt);
+ userPermissions.put(k, perms);
+ log.debug("Loaded user: {} with {} permissions", k, perms.size());
+ }
+ log.info("PropertyBasedRealm configured with {} users", userMap.size());
+ }
+ }
+
+ @Override
+ public Set getPermissions(String identifier) {
+ if (hasIdentifier(identifier)) {
+ return userPermissions.get(identifier);
+ }
+ return new HashSet<>();
+ }
+
+ @Override
+ public boolean hasIdentifier(String identifier) {
+ return userMap.containsKey(identifier);
+ }
+
+ @Override
+ public PermissionResolver getPermissionResolver() {
+ if (gossPermissionResolver != null)
+ return gossPermissionResolver;
+ else
+ return super.getPermissionResolver();
+ }
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/DataSourceBuilder.java b/pnnl.goss.core/src/pnnl/goss/core/server/DataSourceBuilder.java
index 17f09b70..fd5edbec 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/DataSourceBuilder.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/DataSourceBuilder.java
@@ -3,62 +3,64 @@
import java.util.Properties;
/**
- * An interface for building a datasource and adding it to the datasource registry
- * to make Connection's available for connecting to throughout the platform.
- *
+ * An interface for building a datasource and adding it to the datasource
+ * registry to make Connection's available for connecting to throughout the
+ * platform.
+ *
* @author C. Allwardt
*
*/
public interface DataSourceBuilder {
-
- /**
- * A convienence key that can be used to lookup from jndi or GOSS's
- * DataSourceRegistry.
- */
- public static final String DATASOURCE_NAME = "DATASOURCE_NAME";
-
- /**
- * The user parameter should be mapped to this property name.
- */
- public static final String DATASOURCE_USER = "username";
-
- /**
- * The password parameter should be mapped to this property name.
- */
- public static final String DATASOURCE_PASSWORD = "password";
-
- /**
- * The url parameter should be mapped to this property name.
- */
- public static final String DATASOURCE_URL = "url";
-
- /**
- * The driver parameter parameter should be mapped to this property name.
- */
- public static final String DATASOURCE_DRIVER = "driverClassName";
-
- /**
- * Create a datasource and store it for lookup by dsName.
- *
- * @param dsName
- * @param url
- * @param user
- * @param password
- * @param driver
- * @throws ClassNotFoundException
- * @throws Exception
- */
- void create(String dsName, String url, String user, String password, String driver) throws ClassNotFoundException, Exception;
-
- /**
- * Use properties file creation of the datasource. The properties should have at minimum
- * at minimum a DATASOURCE_NAME, DATASOURCE_USER, DATASOURCE_PASSWORD,
- * DATASOURCE_URL, and a DATASOURCE_DRIVER or the implementor should throw an
- * Exception.
- *
- * @param properties
- * @throws ClassNotFoundException
- * @throws Exception
- */
- void create(String dsName, Properties properties) throws ClassNotFoundException, Exception;
+
+ /**
+ * A convienence key that can be used to lookup from jndi or GOSS's
+ * DataSourceRegistry.
+ */
+ public static final String DATASOURCE_NAME = "DATASOURCE_NAME";
+
+ /**
+ * The user parameter should be mapped to this property name.
+ */
+ public static final String DATASOURCE_USER = "username";
+
+ /**
+ * The password parameter should be mapped to this property name.
+ */
+ public static final String DATASOURCE_PASSWORD = "password";
+
+ /**
+ * The url parameter should be mapped to this property name.
+ */
+ public static final String DATASOURCE_URL = "url";
+
+ /**
+ * The driver parameter parameter should be mapped to this property name.
+ */
+ public static final String DATASOURCE_DRIVER = "driverClassName";
+
+ /**
+ * Create a datasource and store it for lookup by dsName.
+ *
+ * @param dsName
+ * @param url
+ * @param user
+ * @param password
+ * @param driver
+ * @throws ClassNotFoundException
+ * @throws Exception
+ */
+ void create(String dsName, String url, String user, String password, String driver)
+ throws ClassNotFoundException, Exception;
+
+ /**
+ * Use properties file creation of the datasource. The properties should have at
+ * minimum at minimum a DATASOURCE_NAME, DATASOURCE_USER, DATASOURCE_PASSWORD,
+ * DATASOURCE_URL, and a DATASOURCE_DRIVER or the implementor should throw an
+ * Exception.
+ *
+ * @param properties
+ * @throws ClassNotFoundException
+ * @throws Exception
+ */
+ void create(String dsName, Properties properties) throws ClassNotFoundException, Exception;
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/DataSourceObject.java b/pnnl.goss.core/src/pnnl/goss/core/server/DataSourceObject.java
index 2775db6c..2734b570 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/DataSourceObject.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/DataSourceObject.java
@@ -1,29 +1,28 @@
package pnnl.goss.core.server;
/**
- * The DataSourceObject interface allows the creation of arbitrary objects
- * to be retrieved by name from the DataSourceRegistry.
- *
+ * The DataSourceObject interface allows the creation of arbitrary objects to be
+ * retrieved by name from the DataSourceRegistry.
+ *
* @author Craig Allwardt
*
*/
public interface DataSourceObject {
- /**
- * The name of the datasource is how the registry will be able to
- * retrieve it from the datastore.
- *
- * @return
- */
- String getName();
-
- /**
- * Some special handling is available for datasources that are
- * jdbc compliant. For instance they can have pooled connections
- * by default.
- *
- * @return
- */
- DataSourceType getDataSourceType();
-
+ /**
+ * The name of the datasource is how the registry will be able to retrieve it
+ * from the datastore.
+ *
+ * @return
+ */
+ String getName();
+
+ /**
+ * Some special handling is available for datasources that are jdbc compliant.
+ * For instance they can have pooled connections by default.
+ *
+ * @return
+ */
+ DataSourceType getDataSourceType();
+
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/DataSourcePooledJdbc.java b/pnnl.goss.core/src/pnnl/goss/core/server/DataSourcePooledJdbc.java
index 48f43889..e440990d 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/DataSourcePooledJdbc.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/DataSourcePooledJdbc.java
@@ -5,6 +5,6 @@
public interface DataSourcePooledJdbc extends DataSourceObject {
- Connection getConnection() throws SQLException;
+ Connection getConnection() throws SQLException;
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/DataSourceRegistry.java b/pnnl.goss.core/src/pnnl/goss/core/server/DataSourceRegistry.java
index 51bae8da..c0e4992a 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/DataSourceRegistry.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/DataSourceRegistry.java
@@ -3,39 +3,39 @@
import java.util.Map;
public interface DataSourceRegistry {
-
- /**
- * Get a DataSourceObject from the registry. If a key
- * does not exist then this call should return null.
- *
- * @param
- * @param key
- * @return
- */
- public DataSourceObject get(String key);
-
- /**
- * Adds a DataSourceObject to the registry, making it available for
- * the entire system.
- *
- * @param key
- * @param obj
- */
- public void add(String key, DataSourceObject obj);
-
- /**
- * Remove DataSourceObject from the registry. If the object doesn't
- * exist this function is silent.
- *
- * @param key
- */
- public void remove(String key);
-
- /**
- * Retrieve a map of names-> datasourcetype that can be retrieved
- * by the user to determine capabilities of datasources.
- *
- * @return
- */
- public Map getAvailable();
+
+ /**
+ * Get a DataSourceObject from the registry. If a key does not exist then this
+ * call should return null.
+ *
+ * @param
+ * @param key
+ * @return
+ */
+ public DataSourceObject get(String key);
+
+ /**
+ * Adds a DataSourceObject to the registry, making it available for the entire
+ * system.
+ *
+ * @param key
+ * @param obj
+ */
+ public void add(String key, DataSourceObject obj);
+
+ /**
+ * Remove DataSourceObject from the registry. If the object doesn't exist this
+ * function is silent.
+ *
+ * @param key
+ */
+ public void remove(String key);
+
+ /**
+ * Retrieve a map of names-> datasourcetype that can be retrieved by the user to
+ * determine capabilities of datasources.
+ *
+ * @return
+ */
+ public Map getAvailable();
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/DataSourceType.java b/pnnl.goss.core/src/pnnl/goss/core/server/DataSourceType.java
index 0b427205..a7064828 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/DataSourceType.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/DataSourceType.java
@@ -1,14 +1,11 @@
package pnnl.goss.core.server;
-
public enum DataSourceType {
- DS_TYPE_JDBC(10),
- DS_TYPE_REST(20),
- DS_TYPE_OTHER(1000);
-
- private final int number;
+ DS_TYPE_JDBC(10), DS_TYPE_REST(20), DS_TYPE_OTHER(1000);
+
+ private final int number;
- private DataSourceType(int number) {
- this.number = number;
- }
-}
\ No newline at end of file
+ private DataSourceType(int number) {
+ this.number = number;
+ }
+}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/HandlerNotFoundException.java b/pnnl.goss.core/src/pnnl/goss/core/server/HandlerNotFoundException.java
index f4b67f63..31445897 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/HandlerNotFoundException.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/HandlerNotFoundException.java
@@ -3,19 +3,19 @@
import pnnl.goss.core.Request;
public class HandlerNotFoundException extends Exception {
-
- private static final long serialVersionUID = 5582363974612539305L;
-
- public HandlerNotFoundException(){
- super();
- }
- public HandlerNotFoundException(Class extends Request> request){
- this(String.format("Handler for %s request was not found!", request.getClass().getName()));
-
- }
-
- public HandlerNotFoundException(String message){
- super(message);
- }
+ private static final long serialVersionUID = 5582363974612539305L;
+
+ public HandlerNotFoundException() {
+ super();
+ }
+
+ public HandlerNotFoundException(Class extends Request> request) {
+ this(String.format("Handler for %s request was not found!", request.getClass().getName()));
+
+ }
+
+ public HandlerNotFoundException(String message) {
+ super(message);
+ }
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/RequestHandler.java b/pnnl.goss.core/src/pnnl/goss/core/server/RequestHandler.java
index 74ba51b2..ea931eb0 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/RequestHandler.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/RequestHandler.java
@@ -8,18 +8,18 @@
public interface RequestHandler extends RequestHandlerInterface {
- /**
- * Explicitly provide a map from request to authorization handler.
- *
- * @return
- */
- Map, Class extends AuthorizationHandler>> getHandles();
-
- /**
- * Handle a request of a specific type of service.
- *
- * @param request
- */
- Response handle(Request request);
-
+ /**
+ * Explicitly provide a map from request to authorization handler.
+ *
+ * @return
+ */
+ Map, Class extends AuthorizationHandler>> getHandles();
+
+ /**
+ * Handle a request of a specific type of service.
+ *
+ * @param request
+ */
+ Response handle(Request request);
+
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/RequestHandlerRegistry.java b/pnnl.goss.core/src/pnnl/goss/core/server/RequestHandlerRegistry.java
index 7fa370b9..e5d307c9 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/RequestHandlerRegistry.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/RequestHandlerRegistry.java
@@ -11,19 +11,18 @@
//import pnnl.goss.core.security.AuthorizationRoleMapper;
public interface RequestHandlerRegistry {
-
- public RequestHandler getHandler(Class extends Request> request) throws HandlerNotFoundException;
-
- public RequestUploadHandler getUploadHandler(String dataType) throws HandlerNotFoundException;
-
- public List list();
-
- public Response handle(Request request) throws HandlerNotFoundException;
-
- public Response handle(String datatype, Serializable data) throws HandlerNotFoundException;
-
- public Response handle(RequestAsync request) throws HandlerNotFoundException;
-
- public boolean checkAccess(Request request, String identifier) throws SystemException;
-}
+ public RequestHandler getHandler(Class extends Request> request) throws HandlerNotFoundException;
+
+ public RequestUploadHandler getUploadHandler(String dataType) throws HandlerNotFoundException;
+
+ public List list();
+
+ public Response handle(Request request) throws HandlerNotFoundException;
+
+ public Response handle(String datatype, Serializable data) throws HandlerNotFoundException;
+
+ public Response handle(RequestAsync request) throws HandlerNotFoundException;
+
+ public boolean checkAccess(Request request, String identifier) throws SystemException;
+}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/RequestUploadHandler.java b/pnnl.goss.core/src/pnnl/goss/core/server/RequestUploadHandler.java
index a5e8d969..81b4ecc3 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/RequestUploadHandler.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/RequestUploadHandler.java
@@ -8,23 +8,23 @@
public interface RequestUploadHandler extends RequestHandlerInterface {
- /**
- * Map all of the datatypes that are handled by the handler. Ideally this
- * should be full class names with perhaps version information, however this
- * is not a requirement. In order for GOSS to understand how to route the
- * request however it does need to be unique system wide.
- *
- * Example: pnnl.gov.powergrid.Bus.getClass().getName()
- *
- * @return
- */
- Map> getHandlerDataTypes();
+ /**
+ * Map all of the datatypes that are handled by the handler. Ideally this should
+ * be full class names with perhaps version information, however this is not a
+ * requirement. In order for GOSS to understand how to route the request however
+ * it does need to be unique system wide.
+ *
+ * Example: pnnl.gov.powergrid.Bus.getClass().getName()
+ *
+ * @return
+ */
+ Map> getHandlerDataTypes();
- /**
- * Handle the upload of data and return a response
- *
- * @param request
- */
- Response upload(String dataType, Serializable data);
+ /**
+ * Handle the upload of data and return a response
+ *
+ * @param request
+ */
+ Response upload(String dataType, Serializable data);
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/ServerControl.java b/pnnl.goss.core/src/pnnl/goss/core/server/ServerControl.java
index ee87d709..728e9535 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/ServerControl.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/ServerControl.java
@@ -3,33 +3,31 @@
import com.northconcepts.exception.SystemException;
public interface ServerControl {
-
- /**
- * Start the server. During the execution of this method the
- * implementor should initialize all properties such that the
- * server can receive Request objects and route them to their
- * appropriate handlers.
- *
- * @throws SystemException
- */
- void start() throws SystemException;
-
- /**
- * Stop the server. During the execution of this method the
- * system should shutdown its method of transport, stop all
- * routing, release any tcp resources that it has available
- * and change the status of the server to not running.
- *
- * @throws SystemException
- */
- void stop() throws SystemException;
-
- /**
- * A plain status of whether the server is able to route Request
- * objects currently.
- *
- * @return
- */
- boolean isRunning();
-
+
+ /**
+ * Start the server. During the execution of this method the implementor should
+ * initialize all properties such that the server can receive Request objects
+ * and route them to their appropriate handlers.
+ *
+ * @throws SystemException
+ */
+ void start() throws SystemException;
+
+ /**
+ * Stop the server. During the execution of this method the system should
+ * shutdown its method of transport, stop all routing, release any tcp resources
+ * that it has available and change the status of the server to not running.
+ *
+ * @throws SystemException
+ */
+ void stop() throws SystemException;
+
+ /**
+ * A plain status of whether the server is able to route Request objects
+ * currently.
+ *
+ * @return
+ */
+ boolean isRunning();
+
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/TokenIdentifierMap.java b/pnnl.goss.core/src/pnnl/goss/core/server/TokenIdentifierMap.java
index 61c1785b..1b22e5b0 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/TokenIdentifierMap.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/TokenIdentifierMap.java
@@ -1,18 +1,18 @@
package pnnl.goss.core.server;
/**
- * TokenIdentifierMap is a container of tokens that have been
- * authenticated with the user login service.
- *
+ * TokenIdentifierMap is a container of tokens that have been authenticated with
+ * the user login service.
+ *
* @author Craig Allwardt
*
*/
public interface TokenIdentifierMap {
-
- String registerIdentifier(String ip, String identifier);
-
- void registerIdentifier(String ip, String token, String identifier);
-
- String getIdentifier(String ip, String token);
-
+
+ String registerIdentifier(String ip, String identifier);
+
+ void registerIdentifier(String ip, String token, String identifier);
+
+ String getIdentifier(String ip, String token);
+
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/impl/Commands.java b/pnnl.goss.core/src/pnnl/goss/core/server/impl/Commands.java
index e8845ec7..570b9a22 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/impl/Commands.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/impl/Commands.java
@@ -2,9 +2,8 @@
import java.util.Map.Entry;
-import org.apache.felix.dm.annotation.api.Component;
-import org.apache.felix.dm.annotation.api.Property;
-import org.apache.felix.dm.annotation.api.ServiceDependency;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
import org.apache.felix.service.command.CommandProcessor;
import pnnl.goss.core.Client.PROTOCOL;
@@ -17,79 +16,80 @@
//import pnnl.goss.core.server.tester.requests.EchoRequest;
import pnnl.goss.core.server.RequestUploadHandler;
-@Component(properties = {
- @Property(name=CommandProcessor.COMMAND_SCOPE, value="gs"),
- @Property(name=CommandProcessor.COMMAND_FUNCTION, value={"listHandlers",
- "listDataSources", "showClientConnections", "help"})},
- provides=Object.class
-)
+@Component(property = {
+ "osgi.command.scope=gs",
+ "osgi.command.function=listHandlers",
+ "osgi.command.function=listDataSources",
+ "osgi.command.function=showClientConnections",
+ "osgi.command.function=help"
+})
public class Commands {
-
- @ServiceDependency
- private volatile RequestHandlerRegistry registry;
- @ServiceDependency
- private volatile DataSourceRegistry dsRegistry;
- @ServiceDependency
- private volatile ClientFactory clientFactory;
-
- public void help(){
- StringBuilder sb = new StringBuilder();
- sb.append("Help for gs commands\n");
- sb.append(" listDataSources - Lists the known datasources that have been registered with the server\n");
- sb.append(" listHandlers - Lists the known request handlers that have been registered with the server.\n");
- System.out.println(sb.toString());
- }
-
- public void showClientConnections(){
-
- for(Entry c: clientFactory.list().entrySet()){
- System.out.println("Client id: " + c.getKey() +
- " protocol " + c.getValue().toString());
- }
- }
-
- public void listDataSources(){
-
- dsRegistry.getAvailable().forEach((k, v)->{
- System.out.println("name: "+ k+" type: "+ v);
- });
-
- }
-
- public void listHandlers(){
- for(RequestHandlerInterface rh: registry.list()){
- if (rh instanceof RequestHandler){
- RequestHandler handler = (RequestHandler) rh;
- handler.getHandles().forEach((k, v)->{
- System.out.println("RequestHandler: "+handler.getClass().getName() + " handles: " + k + " authorized by:" + v);
- });
- }
- else if (rh instanceof RequestUploadHandler) {
- RequestUploadHandler handler = (RequestUploadHandler) rh;
- handler.getHandlerDataTypes().forEach((k, v)->{
- System.out.println("RequestUploadHandler: "+handler.getClass().getName() + " handles data: " + k + " authorized by:" + v);
- });
- }
- else if (rh instanceof AuthorizationHandler) {
- AuthorizationHandler handler = (AuthorizationHandler) rh;
- System.out.println("AuthorizationHandler registered: " + handler.getClass().getName());
- }
-
- }
- }
-
-// public void echo(String message) {
-// EchoRequest request = new EchoRequest(message);
-// registry.handle(request);
-// }
-//
-// public void getEchoHandler() {
-// Optional handler = registry.getHandler(EchoRequest.class);
-// System.out.println("handler is null: "+ handler.isPresent());
-// handler.ifPresent(p-> {
-// System.out.println("Found handler: " + p.getClass().getName());
-// });
-//
-// }
+
+ @Reference
+ private volatile RequestHandlerRegistry registry;
+ @Reference
+ private volatile DataSourceRegistry dsRegistry;
+ @Reference
+ private volatile ClientFactory clientFactory;
+
+ public void help() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Help for gs commands\n");
+ sb.append(" listDataSources - Lists the known datasources that have been registered with the server\n");
+ sb.append(" listHandlers - Lists the known request handlers that have been registered with the server.\n");
+ System.out.println(sb.toString());
+ }
+
+ public void showClientConnections() {
+
+ for (Entry c : clientFactory.list().entrySet()) {
+ System.out.println("Client id: " + c.getKey() +
+ " protocol " + c.getValue().toString());
+ }
+ }
+
+ public void listDataSources() {
+
+ dsRegistry.getAvailable().forEach((k, v) -> {
+ System.out.println("name: " + k + " type: " + v);
+ });
+
+ }
+
+ public void listHandlers() {
+ for (RequestHandlerInterface rh : registry.list()) {
+ if (rh instanceof RequestHandler) {
+ RequestHandler handler = (RequestHandler) rh;
+ handler.getHandles().forEach((k, v) -> {
+ System.out.println("RequestHandler: " + handler.getClass().getName() + " handles: " + k
+ + " authorized by:" + v);
+ });
+ } else if (rh instanceof RequestUploadHandler) {
+ RequestUploadHandler handler = (RequestUploadHandler) rh;
+ handler.getHandlerDataTypes().forEach((k, v) -> {
+ System.out.println("RequestUploadHandler: " + handler.getClass().getName() + " handles data: " + k
+ + " authorized by:" + v);
+ });
+ } else if (rh instanceof AuthorizationHandler) {
+ AuthorizationHandler handler = (AuthorizationHandler) rh;
+ System.out.println("AuthorizationHandler registered: " + handler.getClass().getName());
+ }
+
+ }
+ }
+
+ // public void echo(String message) {
+ // EchoRequest request = new EchoRequest(message);
+ // registry.handle(request);
+ // }
+ //
+ // public void getEchoHandler() {
+ // Optional handler = registry.getHandler(EchoRequest.class);
+ // System.out.println("handler is null: "+ handler.isPresent());
+ // handler.ifPresent(p-> {
+ // System.out.println("Found handler: " + p.getClass().getName());
+ // });
+ //
+ // }
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/impl/GridOpticsServer.java b/pnnl.goss.core/src/pnnl/goss/core/server/impl/GridOpticsServer.java
index 7bab07b7..ed2c2b15 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/impl/GridOpticsServer.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/impl/GridOpticsServer.java
@@ -53,19 +53,12 @@
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
-import java.util.Dictionary;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
-import javax.jms.Connection;
-import javax.jms.ConnectionFactory;
-import javax.jms.DeliveryMode;
-import javax.jms.Destination;
-import javax.jms.JMSException;
-import javax.jms.MessageProducer;
-import javax.jms.Session;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
@@ -79,17 +72,25 @@
import org.apache.activemq.shiro.ShiroPlugin;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.commons.io.FilenameUtils;
-import org.apache.felix.dm.annotation.api.Component;
-import org.apache.felix.dm.annotation.api.ConfigurationDependency;
-import org.apache.felix.dm.annotation.api.ServiceDependency;
-import org.apache.felix.dm.annotation.api.Start;
-import org.apache.felix.dm.annotation.api.Stop;
+import org.apache.shiro.mgt.SecurityManager;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Modified;
+import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.northconcepts.exception.ConnectionCode;
import com.northconcepts.exception.SystemException;
+import jakarta.jms.Connection;
+import jakarta.jms.ConnectionFactory;
+import jakarta.jms.DeliveryMode;
+import jakarta.jms.Destination;
+import jakarta.jms.JMSException;
+import jakarta.jms.MessageProducer;
+import jakarta.jms.Session;
import pnnl.goss.core.GossCoreContants;
import pnnl.goss.core.security.GossRealm;
import pnnl.goss.core.security.GossSecurityManager;
@@ -98,13 +99,12 @@
import pnnl.goss.core.server.RequestHandlerRegistry;
import pnnl.goss.core.server.ServerControl;
-
-@Component
+@Component(service = ServerControl.class, configurationPid = "pnnl.goss.core.server", configurationPolicy = org.osgi.service.component.annotations.ConfigurationPolicy.REQUIRE)
public class GridOpticsServer implements ServerControl {
private static final Logger log = LoggerFactory.getLogger(GridOpticsServer.class);
private static final String CONFIG_PID = "pnnl.goss.core.server";
-
+
private static final String PROP_USE_AUTH = "goss.use.authorization";
private static final String PROP_START_BROKER = "goss.start.broker";
private static final String PROP_CONNECTION_URI = "goss.broker.uri";
@@ -112,30 +112,26 @@ public class GridOpticsServer implements ServerControl {
private static final String PROP_STOMP_TRANSPORT = "goss.stomp.uri";
private static final String PROP_WS_TRANSPORT = "goss.ws.uri";
private static final String PROP_SSL_TRANSPORT = "goss.ssl.uri";
-
+
private static final String PROP_SSL_ENABLED = "ssl.enabled";
private static final String PROP_SSL_CLIENT_KEYSTORE = "client.keystore";
private static final String PROP_SSL_CLIENT_KEYSTORE_PASSWORD = "client.keystore.password";
private static final String PROP_SSL_CLIENT_TRUSTSTORE = "client.truststore";
private static final String PROP_SSL_CLIENT_TRUSTSTORE_PASSWORD = "client.truststore.password";
-
+
private static final String PROP_SSL_SERVER_KEYSTORE = "server.keystore";
private static final String PROP_SSL_SERVER_KEYSTORE_PASSWORD = "server.keystore.password";
private static final String PROP_SSL_SERVER_TRUSTSTORE = "server.truststore";
private static final String PROP_SSL_SERVER_TRUSTSTORE_PASSWORD = "server.truststore.password";
-
+
private static final String PROP_SYSTEM_MANAGER = "goss.system.manager";
private static final String PROP_SYSTEM_MANAGER_PASSWORD = "goss.system.manager.password";
-
+
private BrokerService broker;
private Connection connection;
private Session session;
private Destination destination;
-
- // System manager username/password (required * privleges on the message bus)
- private String systemManager = null;
- private String systemManagerPassword = null;
-
+
// Should we automatically start the broker?
private boolean shouldStartBroker = false;
// The connectionUri to create if shouldStartBroker is set to true.
@@ -146,464 +142,408 @@ public class GridOpticsServer implements ServerControl {
private String sslTransport = null;
// The tcp transport for stomp
private String stompTransport = null;
- // The transport for stomp
+ // The transport for stomp
private String wsTransport = null;
// Topic to listen on for receiving requests
private String requestQueue = null;
-
+
// SSL Parameters
private boolean sslEnabled = false;
private String sslClientKeyStore = null;
- private String sslClientKeyStorePassword = null;
private String sslClientTrustStore = null;
private String sslClientTrustStorePassword = null;
-
+
private String sslServerKeyStore = null;
private String sslServerKeyStorePassword = null;
- private String sslServerTrustStore = null;
private String sslServerTrustStorePassword = null;
-
+
private String gossClockTickTopic = null;
-
+
// A list of consumers all listening to the requestQueue
- private final List consumers = new ArrayList<>();
-
+ private final List consumers = new ArrayList<>();
+
private ConnectionFactory connectionFactory = null;
-
- @ServiceDependency
+
+ @Reference
private volatile SecurityManager securityManager;
- @ServiceDependency
- private volatile SecurityConfig securityConfig;
-
-
- @ServiceDependency
+
+ @Reference
private volatile RequestHandlerRegistry handlerRegistry;
-
- @ServiceDependency
+
+ @Reference
private volatile GossRealm permissionAdapter;
-
-
-
-
+
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
-
-
+
/**
- * Return a default value if the passed string is null or empty,
- * or if the value starts with a ${ (assumes that a property
- * wasn't set in a properties file.).
- *
- * @param value The value to interrogate.
- * @param defaultValue A default value to return if our checks weren't valid
- * @return The value or defaultValue
+ * Return a default value if the passed string is null or empty, or if the value
+ * starts with a ${ (assumes that a property wasn't set in a properties file.).
+ *
+ * @param value
+ * The value to interrogate.
+ * @param defaultValue
+ * A default value to return if our checks weren't valid
+ * @return The value or defaultValue
*/
- private String getProperty(String value, String defaultValue){
- String retValue = defaultValue;
-
- if (value != null && !value.isEmpty()){
- // Let the value pass through because it doesn't
- // start with ${
- if (!value.startsWith("${")){
- retValue = value;
- }
- }
-
- return retValue;
+ private String getProperty(String value, String defaultValue) {
+ String retValue = defaultValue;
+
+ if (value != null && !value.isEmpty()) {
+ // Let the value pass through because it doesn't
+ // start with ${
+ if (!value.startsWith("${")) {
+ retValue = value;
+ }
+ }
+
+ return retValue;
+ }
+
+ @Modified
+ public synchronized void updated(Map properties) throws SystemException {
+
+ if (properties != null) {
+
+ getProperty((String) properties.get(PROP_SYSTEM_MANAGER),
+ "system");
+ getProperty((String) properties.get(PROP_SYSTEM_MANAGER_PASSWORD),
+ "manager");
+
+ shouldStartBroker = Boolean.parseBoolean(
+ getProperty((String) properties.get(PROP_START_BROKER), "true"));
+
+ connectionUri = getProperty((String) properties.get(PROP_CONNECTION_URI),
+ "tcp://localhost:61616");
+
+ openwireTransport = getProperty((String) properties.get(PROP_OPENWIRE_TRANSPORT),
+ "tcp://localhost:61616");
+
+ stompTransport = getProperty((String) properties.get(PROP_STOMP_TRANSPORT),
+ "stomp://localhost:61613");
+
+ // WebSocket transport is optional - set to null by default
+ // since it requires the jetty-websocket-server bundle
+ wsTransport = getProperty((String) properties.get(PROP_WS_TRANSPORT), null);
+
+ requestQueue = getProperty((String) properties.get(GossCoreContants.PROP_REQUEST_QUEUE), "Request");
+
+ gossClockTickTopic = getProperty((String) properties.get(GossCoreContants.PROP_TICK_TOPIC),
+ "goss/system/tick");
+
+ // SSL IS DISABLED BY DEFAULT.
+ sslEnabled = Boolean.parseBoolean(
+ getProperty((String) properties.get(PROP_SSL_ENABLED), "false"));
+
+ sslTransport = getProperty((String) properties.get(PROP_SSL_TRANSPORT), "tcp://localhost:61443");
+
+ sslClientKeyStore = getProperty((String) properties.get(PROP_SSL_CLIENT_KEYSTORE), null);
+ getProperty((String) properties.get(PROP_SSL_CLIENT_KEYSTORE_PASSWORD), null);
+ sslClientTrustStore = getProperty((String) properties.get(PROP_SSL_CLIENT_TRUSTSTORE), null);
+ sslClientTrustStorePassword = getProperty((String) properties.get(PROP_SSL_CLIENT_TRUSTSTORE_PASSWORD),
+ null);
+ sslServerKeyStore = getProperty((String) properties.get(PROP_SSL_SERVER_KEYSTORE), null);
+ sslServerKeyStorePassword = getProperty((String) properties.get(PROP_SSL_SERVER_KEYSTORE_PASSWORD), null);
+ getProperty((String) properties.get(PROP_SSL_SERVER_TRUSTSTORE), null);
+ sslServerTrustStorePassword = getProperty((String) properties.get(PROP_SSL_SERVER_TRUSTSTORE_PASSWORD),
+ null);
+
+ }
+
}
-
-
- @ConfigurationDependency(pid=CONFIG_PID)
- public synchronized void updated(Dictionary properties) throws SystemException {
- if (properties != null) {
-
-
- shouldStartBroker = Boolean.parseBoolean(
- getProperty((String) properties.get(PROP_START_BROKER), "true"));
-
- connectionUri = getProperty((String)properties.get(PROP_CONNECTION_URI),
- "tcp://localhost:61616");
-
- openwireTransport = getProperty((String) properties.get(PROP_OPENWIRE_TRANSPORT),
- "tcp://localhost:61616");
-
- stompTransport = getProperty((String) properties.get(PROP_STOMP_TRANSPORT),
- "stomp://localhost:61613");
-
- wsTransport = getProperty((String) properties.get(PROP_WS_TRANSPORT),
- "ws://localhost:61614");
-
- requestQueue = getProperty((String) properties.get(GossCoreContants.PROP_REQUEST_QUEUE)
- ,"Request");
-
- gossClockTickTopic = getProperty((String) properties.get(GossCoreContants.PROP_TICK_TOPIC)
- , "goss/system/tick");
-
- // SSL IS DISABLED BY DEFAULT.
- sslEnabled = Boolean.parseBoolean(
- getProperty((String) properties.get(PROP_SSL_ENABLED)
- ,"false"));
-
- sslTransport = getProperty((String) properties.get(PROP_SSL_TRANSPORT)
- ,"tcp://localhost:61443");
-
- sslClientKeyStore = getProperty((String) properties.get(PROP_SSL_CLIENT_KEYSTORE)
- ,null);
- sslClientKeyStorePassword = getProperty((String) properties.get(PROP_SSL_CLIENT_KEYSTORE_PASSWORD)
- ,null);
- sslClientTrustStore = getProperty((String) properties.get(PROP_SSL_CLIENT_TRUSTSTORE)
- ,null);
- sslClientTrustStorePassword = getProperty((String) properties.get(PROP_SSL_CLIENT_TRUSTSTORE_PASSWORD)
- ,null);
- sslServerKeyStore = getProperty((String) properties.get(PROP_SSL_SERVER_KEYSTORE)
- ,null);
- sslServerKeyStorePassword = getProperty((String) properties.get(PROP_SSL_SERVER_KEYSTORE_PASSWORD)
- ,null);
- sslServerTrustStore = getProperty((String) properties.get(PROP_SSL_SERVER_TRUSTSTORE)
- ,null);
- sslServerTrustStorePassword = getProperty((String) properties.get(PROP_SSL_SERVER_TRUSTSTORE_PASSWORD)
- ,null);
-
-
- }
-
+
+ public Session getSession() {
+ return session;
}
-
- public Session refreshSession(){
- try{
- session.close();
- }catch (JMSException e) {}
- try{
- session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
- }catch (JMSException e) {
- //attempt to recreate the connection as well
- try{
- connection.close();
- }catch (JMSException e2) {}
- try{
- connection = connectionFactory.createConnection(systemManager, systemManagerPassword);
- connection.start();
- session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
- }catch(JMSException e2){
- e2.printStackTrace();
- }
- }
-
- return session;
- }
-
-
- public Session getSession(){
- return session;
- }
-
+
/**
- * Consults the variables created in the update method for whether
- * there is enough information to create ssl broker and that the
- * ssl.enable property is set to true.
- *
+ * Consults the variables created in the update method for whether there is
+ * enough information to create ssl broker and that the ssl.enable property is
+ * set to true.
+ *
* @return true if the server supports ssl and ssl.enabled is true.
*/
- private boolean shouldUsSsl(){
- // Do we want ssl from the config file?
- boolean useSsl = sslEnabled;
-
- if (useSsl) {
-
- // FileNameUtils.getName will return an empty string if the file
- // does not exist.
- if (FilenameUtils.getName(sslClientKeyStore).isEmpty() ||
- FilenameUtils.getName(sslClientTrustStore).isEmpty())
- {
- useSsl = false;
- }
- }
-
- return useSsl;
-
+ private boolean shouldUsSsl() {
+ // Do we want ssl from the config file?
+ boolean useSsl = sslEnabled;
+
+ if (useSsl) {
+
+ // FileNameUtils.getName will return an empty string if the file
+ // does not exist.
+ if (FilenameUtils.getName(sslClientKeyStore).isEmpty() ||
+ FilenameUtils.getName(sslClientTrustStore).isEmpty()) {
+ useSsl = false;
+ }
+ }
+
+ return useSsl;
+
}
-
+
/**
* Creates a broker with shiro security plugin installed.
- *
- * After this function the broker variable
+ *
+ * After this function the broker variable
*/
- private void createBroker() throws Exception{
- // Create shiro broker plugin
- ShiroPlugin shiroPlugin = new ShiroPlugin();
-
- shiroPlugin.setSecurityManager(securityManager);
- //shiroPlugin.setIniConfig("conf/shiro.ini");
-
- //shiroPlugin.setIni(new IniEnvironment("conf/shiro.ini"));
- //shiroPlugin.getSubjectFilter().setConnectionSubjectFactory(subjectConnectionFactory);
-
- // Configure how we are going to use it.
- //shiroPlugin.setIniConfig(iniConfig);
-
- try {
- if (shouldUsSsl()){
- broker = new SslBrokerService();
-
- KeyManager[] km = getKeyManager(sslServerKeyStore, sslServerKeyStorePassword);
- TrustManager[] tm = getTrustManager(sslClientTrustStore);
- ((SslBrokerService) broker).addSslConnector(sslTransport, km, tm, null);
- log.debug("Starting broker with ssl connector: " + sslTransport);
-
- } else {
- broker = new BrokerService();
- broker.addConnector(openwireTransport);
- broker.addConnector(stompTransport);
- broker.addConnector(wsTransport);
- }
- broker.setPersistent(false);
- broker.setUseJmx(false);
- broker.setPersistenceAdapter(null);
-
- //broker.addConnector(stompTransport);
- broker.setPlugins(new BrokerPlugin[]{shiroPlugin});
-
- broker.start();
- } catch (Exception e) {
- log.error("Error Starting Broker", e);
-
- //System.err.println(e.getMessage());;
- }
+ private void createBroker() throws Exception {
+ // Create shiro broker plugin
+ ShiroPlugin shiroPlugin = new ShiroPlugin();
+
+ shiroPlugin.setSecurityManager(securityManager);
+ // shiroPlugin.setIniConfig("conf/shiro.ini");
+
+ // shiroPlugin.setIni(new IniEnvironment("conf/shiro.ini"));
+ // shiroPlugin.getSubjectFilter().setConnectionSubjectFactory(subjectConnectionFactory);
+
+ // Configure how we are going to use it.
+ // shiroPlugin.setIniConfig(iniConfig);
+
+ try {
+ if (shouldUsSsl()) {
+ broker = new SslBrokerService();
+
+ KeyManager[] km = getKeyManager(sslServerKeyStore, sslServerKeyStorePassword);
+ TrustManager[] tm = getTrustManager(sslClientTrustStore);
+ ((SslBrokerService) broker).addSslConnector(sslTransport, km, tm, null);
+ log.debug("Starting broker with ssl connector: " + sslTransport);
+
+ } else {
+ broker = new BrokerService();
+ broker.addConnector(openwireTransport);
+ broker.addConnector(stompTransport);
+ // Only add WebSocket connector if configured (requires jetty-websocket-server
+ // bundle)
+ if (wsTransport != null && !wsTransport.isEmpty()) {
+ log.debug("Adding WebSocket connector: " + wsTransport);
+ broker.addConnector(wsTransport);
+ }
+ }
+ broker.setPersistent(false);
+ broker.setUseJmx(false);
+ broker.setPersistenceAdapter(null);
+
+ // broker.addConnector(stompTransport);
+ broker.setPlugins(new BrokerPlugin[]{shiroPlugin});
+
+ broker.start();
+ } catch (Exception e) {
+ log.error("Error Starting Broker", e);
+
+ // System.err.println(e.getMessage());;
+ }
}
-
+
/**
- * ClockTick runnable that will be called once a second. *
+ * ClockTick runnable that will be called once a second. *
*/
- private static class ClockTick implements Runnable{
-
- private static int count = 0;
- private volatile Session session;
- private transient MessageProducer producer;
- private Destination destination;
- private boolean sendTick = true;
- private GridOpticsServer server;
- private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
-
- /**
- * Creates the topic and creates the producer to publish data to
- * the to the message bus.
- *
- * @param server
- */
- public ClockTick(GridOpticsServer server){
- session = server.getSession();
- this.server = server;
- // Create a MessageProducer from the Session to the Topic or Queue
+ private static class ClockTick implements Runnable {
+
+ private static int count = 0;
+ private volatile Session session;
+ private transient MessageProducer producer;
+ private Destination destination;
+ private boolean sendTick = true;
+ private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+ /**
+ * Creates the topic and creates the producer to publish data to the to the
+ * message bus.
+ *
+ * @param server
+ */
+ public ClockTick(GridOpticsServer server) {
+ session = server.getSession();
+ // Create a MessageProducer from the Session to the Topic or Queue
try {
- destination = session.createTopic(server.gossClockTickTopic);
- producer = session.createProducer(destination);
- producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
- } catch (JMSException e) {
- e.printStackTrace();
- sendTick = false;
- }
-
- }
-
- /**
- * Called during a task execution. The producer will send a date time string
- * through the message bus.
- */
- @Override
- public void run() {
- if (sendTick) {
- LocalDateTime dt = LocalDateTime.now();
- // current time in UTC time zone
- LocalDateTime localDateTimeUTC = LocalDateTime.now(Clock.systemUTC());
- try {
-
-
- //log.debug(localDateTimeUTC.format(formatter));
- producer.send(session.createTextMessage(localDateTimeUTC.format(formatter)));
-
- }catch (javax.jms.IllegalStateException e) {
- System.out.println("Session closed, attempting to refresh");
- log.warn("Session closed, attempting to refresh");
- // typically happens because the session has timed out, attempt to re-create the session
- session = server.refreshSession();
-
- try{
- producer = session.createProducer(destination);
- producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
- //attempt to resent
- producer.send(session.createTextMessage(localDateTimeUTC.format(formatter)));
- } catch (JMSException e2) {
- e2.printStackTrace();
- }
- } catch (JMSException e) {
- e.printStackTrace();
- }
-
- if (count >= 10000000){
- count = 0;
- }
- else{
- count += 1;
- }
- }
- }
+ destination = session.createTopic(server.gossClockTickTopic);
+ producer = session.createProducer(destination);
+ producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
+ } catch (JMSException e) {
+ e.printStackTrace();
+ sendTick = false;
+ }
+
+ }
+
+ /**
+ * Called during a task execution. The producer will send a date time string
+ * through the message bus.
+ */
+ @Override
+ public void run() {
+ if (sendTick) {
+ LocalDateTime dt = LocalDateTime.now();
+ try {
+ // current time in UTC time zone
+ LocalDateTime localDateTimeUTC = LocalDateTime.now(Clock.systemUTC());
+
+ // log.debug(localDateTimeUTC.format(formatter));
+ producer.send(session.createTextMessage(localDateTimeUTC.format(formatter)));
+ } catch (JMSException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ if (count >= 10000000) {
+ count = 0;
+ } else {
+ count += 1;
+ }
+ }
+ }
}
-
-
+
@Override
- @Start
- public void start() {
-
- if(securityManager!=null){
- systemManager = ((GossSecurityManager)securityManager).getProperty(GossSecurityManager.PROP_SYSTEM_MANAGER,null);//securityConfig.getManagerUser();
- systemManagerPassword = ((GossSecurityManager)securityManager).getProperty(GossSecurityManager.PROP_SYSTEM_MANAGER_PASSWORD,null);;//securityConfig.getManagerPassword();
- }
-
- // If goss should have start the broker service then this will be set.
- // this variable is mapped from goss.start.broker
- if (shouldStartBroker) {
- try {
- createBroker();
- } catch (Exception e) {
- e.printStackTrace();
- broker = null;
- log.error("Error starting broker: ", e);
- throw SystemException.wrap(e);
- }
- }
-
- try {
- if (shouldUsSsl()){
- connectionFactory = new ActiveMQSslConnectionFactory(sslTransport);
-
- ((ActiveMQSslConnectionFactory) connectionFactory).setTrustStore(sslClientTrustStore); //sslClientTrustStore);
- ((ActiveMQSslConnectionFactory) connectionFactory).setTrustStorePassword(sslClientTrustStorePassword); //sslClientTrustStorePassword);
-
- }
- else{
- connectionFactory = new ActiveMQConnectionFactory(openwireTransport);
- }
-
- connection = connectionFactory.createConnection(systemManager, systemManagerPassword);
- connection.start();
- } catch (Exception e) {
- log.debug("Error Connecting to ActiveMQ", e);
- if (shouldStartBroker){
- try {
- if (broker != null){
- broker.stop();
- broker.waitUntilStopped();
- }
- } catch (Exception e1) {
- e1.printStackTrace();
- }
-
- }
- throw SystemException.wrap(e, ConnectionCode.CONNECTION_ERROR);
- }
-
-
- try {
- session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
- destination = session.createQueue(requestQueue);
-
- for(int i=0; i<1; i++){
- System.out.println("Creating consumer: "+i);
- consumers.add(new ServerConsumer()
- .setDestination(destination)
- .setSession(session)
- .setRegistryHandler(handlerRegistry)
- .consume());
- }
- } catch (JMSException e) {
- throw SystemException.wrap(e, ConnectionCode.CONSUMER_ERROR);
- }
-
- scheduler.scheduleAtFixedRate(new ClockTick(this), 1, 1, TimeUnit.SECONDS);
- }
-
+ public void start() throws SystemException {
+ // This method satisfies the ServerControl interface
+ // The actual activation is handled by start(Map) with configuration
+ throw SystemException.wrap(new UnsupportedOperationException(
+ "Use start(Map) for DS activation with configuration"));
+ }
+
+ @Activate
+ public void start(Map properties) {
+ // Apply configuration from ConfigAdmin before starting
+ updated(properties);
+
+ // If goss should have start the broker service then this will be set.
+ // this variable is mapped from goss.start.broker
+ if (shouldStartBroker) {
+ try {
+ createBroker();
+ } catch (Exception e) {
+ e.printStackTrace();
+ broker = null;
+ log.error("Error starting broker: ", e);
+ throw SystemException.wrap(e);
+ }
+ }
+
+ try {
+ if (shouldUsSsl()) {
+ connectionFactory = new ActiveMQSslConnectionFactory(sslTransport);
+
+ ((ActiveMQSslConnectionFactory) connectionFactory).setTrustStore(sslClientTrustStore); // sslClientTrustStore);
+ ((ActiveMQSslConnectionFactory) connectionFactory).setTrustStorePassword(sslClientTrustStorePassword); // sslClientTrustStorePassword);
+
+ } else {
+ connectionFactory = new ActiveMQConnectionFactory(openwireTransport);
+ }
+
+ connection = connectionFactory.createConnection("system", "manager");
+ connection.start();
+ } catch (Exception e) {
+ log.debug("Error Connecting to ActiveMQ", e);
+ if (shouldStartBroker) {
+ try {
+ if (broker != null) {
+ broker.stop();
+ broker.waitUntilStopped();
+ }
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+
+ }
+ throw SystemException.wrap(e, ConnectionCode.CONNECTION_ERROR);
+ }
+
+ try {
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+ destination = session.createQueue(requestQueue);
+
+ for (int i = 0; i < 1; i++) {
+ System.out.println("Creating consumer: " + i);
+ consumers.add(new ServerConsumer()
+ .setDestination(destination)
+ .setSession(session)
+ .setRegistryHandler(handlerRegistry)
+ .consume());
+ }
+ } catch (JMSException e) {
+ throw SystemException.wrap(e, ConnectionCode.CONSUMER_ERROR);
+ }
+
+ scheduler.scheduleAtFixedRate(new ClockTick(this), 1, 1, TimeUnit.SECONDS);
+ }
+
private void createAuthenticatedConnectionFactory(String username, String password) throws JMSException {
-
- ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri);
-
- // Todo find out how we get password from user via config file?
-
- factory.setUserName(username);
- factory.setPassword(password);
- connectionFactory = factory;
-
- }
-
-
- @Override
- @Stop
- public void stop() throws SystemException {
-
- try {
- consumers.clear();
-
- if(session != null) {
- session.close();
- }
- if (connection != null){
- connection.close();
- }
- if (shouldStartBroker){
- if(broker != null) {
- broker.stop();
- broker.waitUntilStopped();
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- SystemException.wrap(e, ConnectionCode.CLOSING_ERROR);
- }
- finally{
- session= null;
- connection = null;
- destination = null;
- broker = null;
- connectionFactory = null;
- }
- }
-
-
-
- @Override
- public boolean isRunning() {
- if (broker == null) return false;
-
- return broker.isStarted();
- }
-
- public static TrustManager[] getTrustManager(String clientTrustStore) throws Exception {
+
+ ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(connectionUri);
+
+ // Todo find out how we get password from user via config file?
+
+ factory.setUserName(username);
+ factory.setPassword(password);
+ connectionFactory = factory;
+
+ }
+
+ @Override
+ @Deactivate
+ public void stop() throws SystemException {
+
+ try {
+ consumers.clear();
+
+ if (session != null) {
+ session.close();
+ }
+ if (connection != null) {
+ connection.close();
+ }
+ if (shouldStartBroker) {
+ if (broker != null) {
+ broker.stop();
+ broker.waitUntilStopped();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ SystemException.wrap(e, ConnectionCode.CLOSING_ERROR);
+ } finally {
+ session = null;
+ connection = null;
+ destination = null;
+ broker = null;
+ connectionFactory = null;
+ }
+ }
+
+ @Override
+ public boolean isRunning() {
+ if (broker == null)
+ return false;
+
+ return broker.isStarted();
+ }
+
+ public static TrustManager[] getTrustManager(String clientTrustStore) throws Exception {
TrustManager[] trustStoreManagers = null;
- KeyStore trustedCertStore = KeyStore.getInstance("jks"); //ActiveMQSslConnectionFactoryTest.KEYSTORE_TYPE);
-
+ KeyStore trustedCertStore = KeyStore.getInstance("jks"); // ActiveMQSslConnectionFactoryTest.KEYSTORE_TYPE);
+
trustedCertStore.load(new FileInputStream(clientTrustStore), null);
- TrustManagerFactory tmf =
- TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
-
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+
tmf.init(trustedCertStore);
trustStoreManagers = tmf.getTrustManagers();
- return trustStoreManagers;
+ return trustStoreManagers;
}
public static KeyManager[] getKeyManager(String serverKeyStore, String serverKeyStorePassword) throws Exception {
- KeyManagerFactory kmf =
- KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
- KeyStore ks = KeyStore.getInstance("jks"); //ActiveMQSslConnectionFactoryTest.KEYSTORE_TYPE);
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ KeyStore ks = KeyStore.getInstance("jks"); // ActiveMQSslConnectionFactoryTest.KEYSTORE_TYPE);
KeyManager[] keystoreManagers = null;
-
+
byte[] sslCert = loadClientCredential(serverKeyStore);
-
-
+
if (sslCert != null && sslCert.length > 0) {
ByteArrayInputStream bin = new ByteArrayInputStream(sslCert);
ks.load(bin, serverKeyStorePassword.toCharArray());
kmf.init(ks, serverKeyStorePassword.toCharArray());
keystoreManagers = kmf.getKeyManagers();
}
- return keystoreManagers;
+ return keystoreManagers;
}
private static byte[] loadClientCredential(String fileName) throws IOException {
@@ -614,7 +554,7 @@ private static byte[] loadClientCredential(String fileName) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[512];
int i = in.read(buf);
- while (i > 0) {
+ while (i > 0) {
out.write(buf, 0, i);
i = in.read(buf);
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/impl/ManagementLauncher.java b/pnnl.goss.core/src/pnnl/goss/core/server/impl/ManagementLauncher.java
index 8e3b71be..62b65e98 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/impl/ManagementLauncher.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/impl/ManagementLauncher.java
@@ -2,10 +2,10 @@
import java.io.Serializable;
-import org.apache.felix.dm.annotation.api.Component;
-import org.apache.felix.dm.annotation.api.ServiceDependency;
-import org.apache.felix.dm.annotation.api.Start;
-import org.apache.felix.dm.annotation.api.Stop;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Deactivate;
import org.apache.http.auth.UsernamePasswordCredentials;
import pnnl.goss.core.Client;
@@ -23,68 +23,62 @@
@Component
public class ManagementLauncher {
- @ServiceDependency
- private volatile ClientFactory clientFactory;
-
- @ServiceDependency
- private volatile ServerControl serverControl;
-
- @ServiceDependency
- private volatile SecurityConfig securityConfig;
-
- @ServiceDependency
- private volatile RequestHandlerRegistry handlerRegistry;
-
- @ServiceDependency
- private volatile DataSourceRegistry datasourceRegistry;
-
- class ResponseEvent implements GossResponseEvent{
- private final Client client;
- private Gson gson = new Gson();
-
- public ResponseEvent(Client client){
- this.client = client;
- }
-
- @Override
- public void onMessage(Serializable response) {
- String responseData = "{}";
- if (response instanceof DataResponse){
- String request = (String)((DataResponse) response).getData();
- if (request.trim().equals("list_handlers")){
- //responseData = "Listing handlers here!";
- responseData = gson.toJson(handlerRegistry.list());
- }
- else if (request.trim().equals("list_datasources")){
- //responseData = "Listing Datasources here!";
- responseData = gson.toJson(datasourceRegistry.getAvailable());
- }
- }
-
-
- System.out.println("On message: "+response.toString());
- client.publish("goss/management/response", responseData);
- }
-
- }
-
- @Start
- public void start(){
- try {
- System.out.println("START "+securityConfig.getManagerUser()+" "+securityConfig.getManagerPassword()+" "+securityConfig);
- Client client = clientFactory.create(PROTOCOL.STOMP,
- new UsernamePasswordCredentials(securityConfig.getManagerUser(), securityConfig.getManagerPassword()), false);
- client.subscribe("/topic/goss/management/request", new ResponseEvent(client));
- client.subscribe("/topic/goss/management/go", new ResponseEvent(client));
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- }
-
- @Stop
- public void stop(){
- System.out.println("Stopping ManagementLauncher");
- }
+ @Reference
+ private volatile ClientFactory clientFactory;
+
+ @Reference
+ private volatile ServerControl serverControl;
+
+ @Reference
+ private volatile RequestHandlerRegistry handlerRegistry;
+
+ @Reference
+ private volatile DataSourceRegistry datasourceRegistry;
+
+ class ResponseEvent implements GossResponseEvent {
+ private final Client client;
+ private Gson gson = new Gson();
+
+ public ResponseEvent(Client client) {
+ this.client = client;
+ }
+
+ @Override
+ public void onMessage(Serializable response) {
+ String responseData = "{}";
+ if (response instanceof DataResponse) {
+ String request = (String) ((DataResponse) response).getData();
+ if (request.trim().equals("list_handlers")) {
+ // responseData = "Listing handlers here!";
+ responseData = gson.toJson(handlerRegistry.list());
+ } else if (request.trim().equals("list_datasources")) {
+ // responseData = "Listing Datasources here!";
+ responseData = gson.toJson(datasourceRegistry.getAvailable());
+ }
+ }
+
+ System.out.println("On message: " + response.toString());
+ client.publish("goss/management/response", responseData);
+ }
+
+ }
+
+ @Activate
+ public void start() {
+ try {
+ Client client = clientFactory.create(PROTOCOL.STOMP,
+ new UsernamePasswordCredentials("system", "manager"));
+ client.subscribe("/topic/goss/management/request", new ResponseEvent(client));
+ client.subscribe("/topic/goss/management/go", new ResponseEvent(client));
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+
+ @Deactivate
+ public void stop() {
+ System.out.println("Stopping ManagementLauncher");
+ }
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/impl/PooledSqlServiceFactory.java b/pnnl.goss.core/src/pnnl/goss/core/server/impl/PooledSqlServiceFactory.java
deleted file mode 100644
index d02bf185..00000000
--- a/pnnl.goss.core/src/pnnl/goss/core/server/impl/PooledSqlServiceFactory.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package pnnl.goss.core.server.impl;
-
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.felix.dm.DependencyManager;
-import org.apache.felix.dm.annotation.api.Component;
-import org.apache.felix.dm.annotation.api.Inject;
-import org.apache.felix.dm.annotation.api.Property;
-import org.apache.felix.dm.annotation.api.ServiceDependency;
-import org.osgi.framework.Constants;
-import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedServiceFactory;
-
-import pnnl.goss.core.server.DataSourceBuilder;
-import pnnl.goss.core.server.DataSourceObject;
-import pnnl.goss.core.server.DataSourcePooledJdbc;
-import pnnl.goss.core.server.DataSourceRegistry;
-import pnnl.goss.core.server.TokenIdentifierMap;
-
-@Component(
- properties=@Property(
- name=Constants.SERVICE_PID,
- value="pnnl.goss.sql.datasource")
-)
-public class PooledSqlServiceFactory implements ManagedServiceFactory{
-
- @Inject
- private volatile DependencyManager dm;
-
- // Map of service pid to the actual component. Note we use long form
- // of component because it is different than the annotation component
- // used on the top of the class.
- private final Map components = new ConcurrentHashMap<>();
-
- @Override
- public String getName() {
- return "Pooled Sql Service Factory";
- }
-
- private boolean isRequiredKey(String k){
- switch (k){
- case DataSourceBuilder.DATASOURCE_USER:
- case DataSourceBuilder.DATASOURCE_PASSWORD:
- case DataSourceBuilder.DATASOURCE_URL:
- case "name":
- return true;
-
- default:
- return false;
- }
- }
-
- @Override
- public void updated(String pid, Dictionary properties) throws ConfigurationException {
- Map props = new HashMap<>();
- Map otherProps = new HashMap<>();
-
- Enumeration keys = properties.keys();
-
- while(keys.hasMoreElements()){
- String key= keys.nextElement();
-
- String value = (String)properties.get(key);
-
- if (isRequiredKey(key)){
- if (value == null || value.isEmpty()){
- throw new ConfigurationException(key, "Must be specified!");
- }
- props.put(key, value);
- }
- else{
- if (value != null && value.isEmpty()){
- otherProps.put(key, value);
- }
- }
- }
-
- String datasourceDriver = "com.mysql.jdbc.Driver";
- if (otherProps.containsKey(DataSourceBuilder.DATASOURCE_DRIVER)){
- datasourceDriver = otherProps.get(DataSourceBuilder.DATASOURCE_DRIVER);
- otherProps.remove(DataSourceBuilder.DATASOURCE_DRIVER);
- }
-
- PooledSqlServiceImpl service = new PooledSqlServiceImpl(
- props.get("name"),
- props.get(DataSourceBuilder.DATASOURCE_URL),
- props.get(DataSourceBuilder.DATASOURCE_USER),
- props.get(DataSourceBuilder.DATASOURCE_PASSWORD),
- datasourceDriver, otherProps);
-
- org.apache.felix.dm.Component c = dm.createComponent()
- .setInterface(DataSourceObject.class.getName(), null).setImplementation(service);
-
- components.put(pid, c);
- dm.add(c);
- }
-
- @Override
- public void deleted(String pid) {
- dm.remove(components.remove(pid));
- }
-
-
-}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/impl/PooledSqlServiceImpl.java b/pnnl.goss.core/src/pnnl/goss/core/server/impl/PooledSqlServiceImpl.java
index 3dbfba03..766dbd6c 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/impl/PooledSqlServiceImpl.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/impl/PooledSqlServiceImpl.java
@@ -1,91 +1,90 @@
-package pnnl.goss.core.server.impl;
-
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import javax.sql.DataSource;
-
-import org.apache.commons.dbcp.BasicDataSource;
-import org.apache.commons.dbcp.BasicDataSourceFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import pnnl.goss.core.server.DataSourceBuilder;
-import pnnl.goss.core.server.DataSourceObject;
-import pnnl.goss.core.server.DataSourcePooledJdbc;
-import pnnl.goss.core.server.DataSourceType;
-
-public class PooledSqlServiceImpl implements DataSourceObject, DataSourcePooledJdbc {
- private static final Logger log = LoggerFactory.getLogger(PooledSqlServiceImpl.class);
- private final String username;
- private final String url;
- private final String password;
- private final String driverClass;
- private final String name;
- private final Map customizations;
- private DataSource dataSource;
-
-
- public PooledSqlServiceImpl(String datasource_name, String url, String username, String password, String driver, Map otherProperties) {
- this.name = datasource_name;
- this.url = url;
- this.password = password;
- this.driverClass = driver;
- this.username = username;
- this.customizations = otherProperties;
- this.createDataSource();
- }
-
- private void createDataSource(){
- Properties propertiesForDataSource = new Properties();
- propertiesForDataSource.setProperty("username", username);
- propertiesForDataSource.setProperty("password", password);
- propertiesForDataSource.setProperty("url", url);
- propertiesForDataSource.setProperty("driverClassName", driverClass);
-
- propertiesForDataSource.putAll(customizations);
-
-
- if (!propertiesForDataSource.containsKey("maxOpenPreparedStatements")){
- propertiesForDataSource.setProperty("maxOpenPreparedStatements", "10");
- }
-
- log.debug(String.format("Creating datasource: %s, User: %s, URL: %s)", this.name, username, url));
-
- try {
- Class.forName(propertiesForDataSource.getProperty("driverClassName"));
- dataSource = BasicDataSourceFactory.createDataSource(propertiesForDataSource);
- } catch (ClassNotFoundException e) {
- dataSource = null;
- e.printStackTrace();
- } catch (Exception e) {
- dataSource = null;
- e.printStackTrace();
- }
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public DataSourceType getDataSourceType() {
- return DataSourceType.DS_TYPE_JDBC;
- }
-
- @Override
- public Connection getConnection() throws SQLException {
-
- if (dataSource == null){
- throw new SQLException("Invalid datasource.");
- }
-
- return dataSource.getConnection();
- }
-
-}
+package pnnl.goss.core.server.impl;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.sql.DataSource;
+
+import org.apache.commons.dbcp.BasicDataSource;
+import org.apache.commons.dbcp.BasicDataSourceFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import pnnl.goss.core.server.DataSourceBuilder;
+import pnnl.goss.core.server.DataSourceObject;
+import pnnl.goss.core.server.DataSourcePooledJdbc;
+import pnnl.goss.core.server.DataSourceType;
+
+public class PooledSqlServiceImpl implements DataSourceObject, DataSourcePooledJdbc {
+ private static final Logger log = LoggerFactory.getLogger(PooledSqlServiceImpl.class);
+ private final String username;
+ private final String url;
+ private final String password;
+ private final String driverClass;
+ private final String name;
+ private final Map customizations;
+ private DataSource dataSource;
+
+ public PooledSqlServiceImpl(String datasource_name, String url, String username, String password, String driver,
+ Map otherProperties) {
+ this.name = datasource_name;
+ this.url = url;
+ this.password = password;
+ this.driverClass = driver;
+ this.username = username;
+ this.customizations = otherProperties;
+ this.createDataSource();
+ }
+
+ private void createDataSource() {
+ Properties propertiesForDataSource = new Properties();
+ propertiesForDataSource.setProperty("username", username);
+ propertiesForDataSource.setProperty("password", password);
+ propertiesForDataSource.setProperty("url", url);
+ propertiesForDataSource.setProperty("driverClassName", driverClass);
+
+ propertiesForDataSource.putAll(customizations);
+
+ if (!propertiesForDataSource.containsKey("maxOpenPreparedStatements")) {
+ propertiesForDataSource.setProperty("maxOpenPreparedStatements", "10");
+ }
+
+ log.debug(String.format("Creating datasource: %s, User: %s, URL: %s)", this.name, username, url));
+
+ try {
+ Class.forName(propertiesForDataSource.getProperty("driverClassName"));
+ dataSource = BasicDataSourceFactory.createDataSource(propertiesForDataSource);
+ } catch (ClassNotFoundException e) {
+ dataSource = null;
+ e.printStackTrace();
+ } catch (Exception e) {
+ dataSource = null;
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public DataSourceType getDataSourceType() {
+ return DataSourceType.DS_TYPE_JDBC;
+ }
+
+ @Override
+ public Connection getConnection() throws SQLException {
+
+ if (dataSource == null) {
+ throw new SQLException("Invalid datasource.");
+ }
+
+ return dataSource.getConnection();
+ }
+
+}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/impl/ServerConsumer.java b/pnnl.goss.core/src/pnnl/goss/core/server/impl/ServerConsumer.java
index ba974a1a..ecebc814 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/impl/ServerConsumer.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/impl/ServerConsumer.java
@@ -46,10 +46,10 @@
import java.util.Optional;
-import javax.jms.Destination;
-import javax.jms.JMSException;
-import javax.jms.MessageConsumer;
-import javax.jms.Session;
+import jakarta.jms.Destination;
+import jakarta.jms.JMSException;
+import jakarta.jms.MessageConsumer;
+import jakarta.jms.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -64,35 +64,35 @@ public class ServerConsumer {
private static final Logger log = LoggerFactory.getLogger(ServerConsumer.class);
private Session session;
- private Destination destination;
+ private Destination destination;
private RequestHandlerRegistry handlerRegistry;
-
- public ServerConsumer setDestination(Destination destination){
- this.destination = Optional.of(destination).get();
- return this;
+
+ public ServerConsumer setDestination(Destination destination) {
+ this.destination = Optional.of(destination).get();
+ return this;
}
-
- public ServerConsumer setSession(Session session){
- this.session = Optional.of(session).get();
- return this;
+
+ public ServerConsumer setSession(Session session) {
+ this.session = Optional.of(session).get();
+ return this;
}
-
- public ServerConsumer setRegistryHandler(RequestHandlerRegistry registry){
- this.handlerRegistry = registry;
- return this;
+
+ public ServerConsumer setRegistryHandler(RequestHandlerRegistry registry) {
+ this.handlerRegistry = registry;
+ return this;
}
-
- public ServerConsumer consume() throws SystemException{
- log.debug("consume");
- try {
- MessageConsumer consumer = session.createConsumer(destination);
- consumer.setMessageListener(new ServerListener()
- .setSession(session)
- .setRegistryHandler(handlerRegistry));
- } catch (JMSException e) {
- SystemException.wrap(e, ConnectionCode.CONSUMER_ERROR);
- }
- log.debug("end consume");
- return this;
+
+ public ServerConsumer consume() throws SystemException {
+ log.debug("consume");
+ try {
+ MessageConsumer consumer = session.createConsumer(destination);
+ consumer.setMessageListener(new ServerListener()
+ .setSession(session)
+ .setRegistryHandler(handlerRegistry));
+ } catch (JMSException e) {
+ SystemException.wrap(e, ConnectionCode.CONSUMER_ERROR);
+ }
+ log.debug("end consume");
+ return this;
}
-}
\ No newline at end of file
+}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/impl/ServerListener.java b/pnnl.goss.core/src/pnnl/goss/core/server/impl/ServerListener.java
index db46e2d1..5dced4f1 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/impl/ServerListener.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/impl/ServerListener.java
@@ -46,12 +46,12 @@
import java.io.Serializable;
-import javax.jms.InvalidDestinationException;
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.MessageListener;
-import javax.jms.ObjectMessage;
-import javax.jms.Session;
+import jakarta.jms.InvalidDestinationException;
+import jakarta.jms.JMSException;
+import jakarta.jms.Message;
+import jakarta.jms.MessageListener;
+import jakarta.jms.ObjectMessage;
+import jakarta.jms.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -76,28 +76,26 @@
public class ServerListener implements MessageListener {
private static final Logger log = LoggerFactory.getLogger(ServerListener.class);
-
-
+
private volatile RequestHandlerRegistry handlerRegistry;
-
+
private Session session;
boolean useAuth = true;
-
- public ServerListener setSession(Session session){
- this.session = session;
- return this;
+ public ServerListener setSession(Session session) {
+ this.session = session;
+ return this;
}
-
- public ServerListener setRegistryHandler(RequestHandlerRegistry registry){
- this.handlerRegistry = registry;
- return this;
+
+ public ServerListener setRegistryHandler(RequestHandlerRegistry registry) {
+ this.handlerRegistry = registry;
+ return this;
}
public void onMessage(Message message1) {
final Message message = message1;
- log.debug("Message of type: "+ message1.getClass() + " received");
+ log.debug("Message of type: " + message1.getClass() + " received");
Thread thread = new Thread(new Runnable() {
public void run() {
@@ -106,31 +104,32 @@ public void run() {
try {
ObjectMessage objectMessage = (ObjectMessage) message;
- // Assume that the passed object on the wire is of type Request. An error will be thrown
+ // Assume that the passed object on the wire is of type Request. An error will
+ // be thrown
// if that is not the case.
Request request = (Request) objectMessage.getObject();
log.debug("Handling request type: " + request.getClass());
-
+
if (useAuth) {
- if (!message.getBooleanProperty(SecurityConstants.HAS_SUBJECT_HEADER)){
- log.error("Identifier not set in message header");
- serverPublisher.sendErrror("Invalid subject in message!", message.getJMSReplyTo());
- return;
-
- }
-
- String identifier = message.getStringProperty(SecurityConstants.SUBJECT_HEADER);
- username = identifier;
- boolean allowed = handlerRegistry.checkAccess(request, identifier);
-
- if (!allowed){
- log.info("Access denied to "+identifier+" for request type "+request.getClass().getName());
- serverPublisher.sendErrror("Access Denied for the requested data", message.getJMSReplyTo());
- return;
- }
- log.debug("Access allowed to the request");
+ if (!message.getBooleanProperty(SecurityConstants.HAS_SUBJECT_HEADER)) {
+ log.error("Identifier not set in message header");
+ serverPublisher.sendErrror("Invalid subject in message!", message.getJMSReplyTo());
+ return;
+
+ }
+
+ String identifier = message.getStringProperty(SecurityConstants.SUBJECT_HEADER);
+
+ boolean allowed = handlerRegistry.checkAccess(request, identifier);
+
+ if (!allowed) {
+ log.info("Access denied to " + identifier + " for request type "
+ + request.getClass().getName());
+ serverPublisher.sendErrror("Access Denied for the requested data", message.getJMSReplyTo());
+ return;
+ }
+ log.debug("Access allowed to the request");
}
-
if (request instanceof UploadRequest) {
@@ -139,21 +138,24 @@ public void run() {
String dataType = uploadRequest.getDataType();
Serializable data = uploadRequest.getData();
-
+
UploadResponse response = (UploadResponse) handlerRegistry.handle(dataType, data);
response.setId(request.getId());
serverPublisher.sendResponse(response, message.getJMSReplyTo());
- //TODO: Added capability for event processing without upload. Example - FNCS
- /*UploadResponse response = new UploadResponse(true);
- response.setId(request.getId());
- serverPublisher.sendResponse(response, message.getJMSReplyTo());*/
+ // TODO: Added capability for event processing without upload. Example - FNCS
+ /*
+ * UploadResponse response = new UploadResponse(true);
+ * response.setId(request.getId()); serverPublisher.sendResponse(response,
+ * message.getJMSReplyTo());
+ */
if (data instanceof Event) {
DataResponse dataResponse = new DataResponse();
dataResponse.setUsername(username);
dataResponse.setData(data);
- serverPublisher.sendEvent(dataResponse, data.getClass().getName().substring(data.getClass().getName().lastIndexOf(".") + 1));
+ serverPublisher.sendEvent(dataResponse, data.getClass().getName()
+ .substring(data.getClass().getName().lastIndexOf(".") + 1));
serverPublisher.close();
}
@@ -167,57 +169,57 @@ public void run() {
}
} else if (request instanceof RequestAsync) {
- RequestAsync requestAsync = (RequestAsync)request;
+ RequestAsync requestAsync = (RequestAsync) request;
- //AbstractRequestHandler handler = handlerService.getHandler(request);
+ // AbstractRequestHandler handler = handlerService.getHandler(request);
DataResponse response = (DataResponse) handlerRegistry.handle(request);
response.setUsername(username);
response.setId(request.getId());
if (message.getStringProperty("RESPONSE_FORMAT") != null) {
- serverPublisher.sendResponse(response, message.getJMSReplyTo(), RESPONSE_FORMAT.valueOf(message.getStringProperty("RESPONSE_FORMAT")));
- }
- else {
+ serverPublisher.sendResponse(response, message.getJMSReplyTo(),
+ RESPONSE_FORMAT.valueOf(message.getStringProperty("RESPONSE_FORMAT")));
+ } else {
serverPublisher.sendResponse(response, message.getJMSReplyTo(), null);
}
- while(response.isResponseComplete()==false){
+ while (response.isResponseComplete() == false) {
Thread.sleep(requestAsync.getFrequency());
response = (DataResponse) handlerRegistry.handle(request);
response.setId(request.getId());
if (message.getStringProperty("RESPONSE_FORMAT") != null) {
- serverPublisher.sendResponse(response, message.getJMSReplyTo(), RESPONSE_FORMAT.valueOf(message.getStringProperty("RESPONSE_FORMAT")));
- }
- else {
+ serverPublisher.sendResponse(response, message.getJMSReplyTo(),
+ RESPONSE_FORMAT.valueOf(message.getStringProperty("RESPONSE_FORMAT")));
+ } else {
serverPublisher.sendResponse(response, message.getJMSReplyTo(), null);
}
}
- }
- else {
+ } else {
DataResponse response = (DataResponse) handlerRegistry.handle(request);
- //DataResponse response = (DataResponse) ServerRequestHandler.handle(request);
+ // DataResponse response = (DataResponse) ServerRequestHandler.handle(request);
response.setResponseComplete(true);
response.setUsername(username);
response.setId(request.getId());
if (message.getStringProperty("RESPONSE_FORMAT") != null)
- serverPublisher.sendResponse(response, message.getJMSReplyTo(), RESPONSE_FORMAT.valueOf(message.getStringProperty("RESPONSE_FORMAT")));
+ serverPublisher.sendResponse(response, message.getJMSReplyTo(),
+ RESPONSE_FORMAT.valueOf(message.getStringProperty("RESPONSE_FORMAT")));
else
serverPublisher.sendResponse(response, message.getJMSReplyTo(), null);
- //System.out.println(System.currentTimeMillis());
- }
+ // System.out.println(System.currentTimeMillis());
+ }
} catch (InvalidDestinationException e) {
e.printStackTrace();
try {
- DataResponse response = new DataResponse(new DataError("Exception occured: "+e.getMessage()));
- response.setUsername(username);
- serverPublisher.sendResponse(response , message.getJMSReplyTo());
+ serverPublisher.sendResponse(
+ new DataResponse(new DataError("Exception occured: " + e.getMessage())),
+ message.getJMSReplyTo());
} catch (JMSException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
@@ -227,19 +229,16 @@ public void run() {
e.printStackTrace();
try {
- DataResponse response = new DataResponse(new DataError("Exception occured"));
- response.setUsername(username);
- serverPublisher.sendResponse(response , message.getJMSReplyTo());
+ serverPublisher.sendResponse(new DataResponse(new DataError("Exception occured")),
+ message.getJMSReplyTo());
} catch (JMSException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
serverPublisher.close();
- }
- catch(Throwable t){
+ } catch (Throwable t) {
t.printStackTrace();
- }
- finally {
+ } finally {
}
@@ -251,4 +250,4 @@ public void run() {
}
-}
\ No newline at end of file
+}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/impl/ServerPublisher.java b/pnnl.goss.core/src/pnnl/goss/core/server/impl/ServerPublisher.java
index 71de6960..492cd316 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/impl/ServerPublisher.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/impl/ServerPublisher.java
@@ -11,7 +11,7 @@
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
@@ -44,13 +44,12 @@
*/
package pnnl.goss.core.server.impl;
-
-import javax.jms.Destination;
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.ObjectMessage;
-import javax.jms.Session;
-import javax.jms.TextMessage;
+import jakarta.jms.Destination;
+import jakarta.jms.JMSException;
+import jakarta.jms.Message;
+import jakarta.jms.ObjectMessage;
+import jakarta.jms.Session;
+import jakarta.jms.TextMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -64,76 +63,80 @@
public class ServerPublisher {
- private final Session session;
-
- private static final Logger log = LoggerFactory.getLogger(ServerPublisher.class);
-
- public ServerPublisher(Session session) {
- this.session = session;
- }
-
- public void sendErrror(String errorString, Destination destination) throws JMSException{
- DataResponse errResp = new DataResponse(new DataError(errorString));
- errResp.setResponseComplete(true);
- sendResponse(errResp, destination);
- }
-
- public void sendResponse(Response response, Destination destination)
- throws JMSException {
-
- ObjectMessage message = session.createObjectMessage(response);
- //System.out.println("Sending response for QueryId: " + response.getId() + " on destination: " + destination);
- log.debug("Sending response for QueryId: " + response.getId() + " on destination: " + destination);
- session.createProducer(destination).send(message); //producer.send(destination, message);
-
- }
-
- public void sendResponse(Response response, Destination destination,
- RESPONSE_FORMAT responseFormat) throws JMSException {
-
- Message message = null;
-
- if (responseFormat == null)
- message = session.createObjectMessage(response);
- else if (responseFormat == RESPONSE_FORMAT.XML) {
- XStream xStream = new XStream();
- String xml = xStream.toXML(((DataResponse) response).getData());
- message = session.createTextMessage(xml);
- }
-
- //System.out.println("Sending response for QueryId: " + response.getId() + " on destination: " + destination);
- log.debug("Sending response for QueryId: " + response.getId() + " on destination: " + destination);
- //producer.send(destination, message);
- session.createProducer(destination).send(message);
-
- }
-
- public void sendEvent(Response response, String destinationName)
- throws JMSException {
- Destination destination = session.createTopic(destinationName);
- ObjectMessage message = session.createObjectMessage(response);
- //System.out.println("Sending response for QueryId: on destination: "+ destination);
- log.debug("Sending response for QueryId: on destination: "+ destination);
- //producer.send(destination, message);
- session.createProducer(destination).send(message);
- }
-
- public void sendEvent(String message, String destinationName)
- throws JMSException {
- Destination destination = session.createTopic(destinationName);
- TextMessage response = session.createTextMessage(message);
-
- //System.out.println("Sending response for QueryId: on destination: "+ destination);
- //producer.send(destination, response);
- session.createProducer(destination).send(response);
- }
-
- public void close() {
-// try {
-// session.close();
-// } catch (JMSException e) {
-// e.printStackTrace();
-// }
- }
+ private final Session session;
+
+ private static final Logger log = LoggerFactory.getLogger(ServerPublisher.class);
+
+ public ServerPublisher(Session session) {
+ this.session = session;
+ }
+
+ public void sendErrror(String errorString, Destination destination) throws JMSException {
+ DataResponse errResp = new DataResponse(new DataError(errorString));
+ errResp.setResponseComplete(true);
+ sendResponse(errResp, destination);
+ }
+
+ public void sendResponse(Response response, Destination destination)
+ throws JMSException {
+
+ ObjectMessage message = session.createObjectMessage(response);
+ // System.out.println("Sending response for QueryId: " + response.getId() + " on
+ // destination: " + destination);
+ log.debug("Sending response for QueryId: " + response.getId() + " on destination: " + destination);
+ session.createProducer(destination).send(message); // producer.send(destination, message);
+
+ }
+
+ public void sendResponse(Response response, Destination destination,
+ RESPONSE_FORMAT responseFormat) throws JMSException {
+
+ Message message = null;
+
+ if (responseFormat == null)
+ message = session.createObjectMessage(response);
+ else if (responseFormat == RESPONSE_FORMAT.XML) {
+ XStream xStream = new XStream();
+ String xml = xStream.toXML(((DataResponse) response).getData());
+ message = session.createTextMessage(xml);
+ }
+
+ // System.out.println("Sending response for QueryId: " + response.getId() + " on
+ // destination: " + destination);
+ log.debug("Sending response for QueryId: " + response.getId() + " on destination: " + destination);
+ // producer.send(destination, message);
+ session.createProducer(destination).send(message);
+
+ }
+
+ public void sendEvent(Response response, String destinationName)
+ throws JMSException {
+ Destination destination = session.createTopic(destinationName);
+ ObjectMessage message = session.createObjectMessage(response);
+ // System.out.println("Sending response for QueryId: on destination: "+
+ // destination);
+ log.debug("Sending response for QueryId: on destination: " + destination);
+ // producer.send(destination, message);
+ session.createProducer(destination).send(message);
+ }
+
+ public void sendEvent(String message, String destinationName)
+ throws JMSException {
+ Destination destination = session.createTopic(destinationName);
+ TextMessage response = session.createTextMessage(message);
+
+ // System.out.println("Sending response for QueryId: on destination: "+
+ // destination);
+ // producer.send(destination, response);
+ session.createProducer(destination).send(response);
+ }
+
+ public void close() {
+ // try {
+ // session.close();
+ // } catch (JMSException e) {
+ // e.printStackTrace();
+ // }
+ }
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/impl/TokenMap.java b/pnnl.goss.core/src/pnnl/goss/core/server/impl/TokenMap.java
index 49d7e684..3372dce5 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/impl/TokenMap.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/impl/TokenMap.java
@@ -5,75 +5,75 @@
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
-import org.apache.felix.dm.annotation.api.Component;
+import org.osgi.service.component.annotations.Component;
import pnnl.goss.core.server.TokenIdentifierMap;
-@Component
-public class TokenMap implements TokenIdentifierMap{
-
- private static final long ONE_MINUTE_IN_MILLIS=60000;
-
- private class MapItem{
- public MapItem(String ipAddress, String token, String identifier){
- this.lastRequested = new Date();
- this.token = token;
- this.ipAddress = ipAddress;
- this.identifier = identifier;
- }
-
- public void updateTime(){
- lastRequested = new Date();
- }
- public Date lastRequested;
- public String token;
- public String ipAddress;
- public String identifier;
- }
-
- private Map registeredTokens = new ConcurrentHashMap<>();
- private int timeoutMinutes = 5;
-
- @Override
- public String registerIdentifier(String ip, String identifier) {
- String token = UUID.randomUUID().toString();
- registerIdentifier(ip, token, identifier);
- return token;
- }
-
- @Override
- public void registerIdentifier(String ip, String token, String identifier) {
- MapItem item = new MapItem(ip, token, identifier);
- registeredTokens.put(token, item);
- }
-
- @Override
- public String getIdentifier(String ip, String token) {
- String identifier = null;
- if (isValid(ip, token)){
- identifier = registeredTokens.get(token).identifier;
- }
- return identifier;
- }
-
- private boolean isValid(String ip, String token){
- boolean valid = false;
-
- if (registeredTokens.containsKey(token)){
- MapItem item = registeredTokens.get(token);
-
- if (item.ipAddress.equals(ip) && item.token.equals(token)){
- Date beforeTime = new Date(new Date().getTime() + timeoutMinutes * ONE_MINUTE_IN_MILLIS);
-
- if (item.lastRequested.before(beforeTime)){
- item.updateTime();
- valid = true;
- }
- }
- }
-
- return valid;
- }
-
-
+@Component(service = TokenIdentifierMap.class)
+public class TokenMap implements TokenIdentifierMap {
+
+ private static final long ONE_MINUTE_IN_MILLIS = 60000;
+
+ private class MapItem {
+ public MapItem(String ipAddress, String token, String identifier) {
+ this.lastRequested = new Date();
+ this.token = token;
+ this.ipAddress = ipAddress;
+ this.identifier = identifier;
+ }
+
+ public void updateTime() {
+ lastRequested = new Date();
+ }
+
+ public Date lastRequested;
+ public String token;
+ public String ipAddress;
+ public String identifier;
+ }
+
+ private Map registeredTokens = new ConcurrentHashMap<>();
+ private int timeoutMinutes = 5;
+
+ @Override
+ public String registerIdentifier(String ip, String identifier) {
+ String token = UUID.randomUUID().toString();
+ registerIdentifier(ip, token, identifier);
+ return token;
+ }
+
+ @Override
+ public void registerIdentifier(String ip, String token, String identifier) {
+ MapItem item = new MapItem(ip, token, identifier);
+ registeredTokens.put(token, item);
+ }
+
+ @Override
+ public String getIdentifier(String ip, String token) {
+ String identifier = null;
+ if (isValid(ip, token)) {
+ identifier = registeredTokens.get(token).identifier;
+ }
+ return identifier;
+ }
+
+ private boolean isValid(String ip, String token) {
+ boolean valid = false;
+
+ if (registeredTokens.containsKey(token)) {
+ MapItem item = registeredTokens.get(token);
+
+ if (item.ipAddress.equals(ip) && item.token.equals(token)) {
+ Date beforeTime = new Date(new Date().getTime() + timeoutMinutes * ONE_MINUTE_IN_MILLIS);
+
+ if (item.lastRequested.before(beforeTime)) {
+ item.updateTime();
+ valid = true;
+ }
+ }
+ }
+
+ return valid;
+ }
+
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/web/Activator.java b/pnnl.goss.core/src/pnnl/goss/core/server/web/Activator.java
deleted file mode 100644
index cdac0d82..00000000
--- a/pnnl.goss.core/src/pnnl/goss/core/server/web/Activator.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package pnnl.goss.core.server.web;
-
-import java.util.Hashtable;
-
-import javax.servlet.Filter;
-
-import org.apache.felix.dm.DependencyActivatorBase;
-import org.apache.felix.dm.DependencyManager;
-import org.apache.felix.dm.annotation.api.ServiceDependency;
-import org.apache.shiro.mgt.SecurityManager;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.service.http.HttpContext;
-import org.osgi.service.http.HttpService;
-
-import pnnl.goss.core.server.TokenIdentifierMap;
-
-public class Activator extends DependencyActivatorBase {
-
- private static String WEB_CONFIG_PID = "pnnl.goss.core.server.web";
-
-// @ServiceDependency
-// private volatile HttpService httpService;
-
- @Override
- @SuppressWarnings({ "rawtypes", "unchecked" })
- public void init(BundleContext context, DependencyManager manager)
- throws Exception {
-
-
- Hashtable xDomainProps = new Hashtable();
- xDomainProps.put("pattern", ".*");
- xDomainProps.put("service.ranking", 10);
-
- // Try and keep httpcontext of gosscontext across the board.
- Hashtable loggedInFilterProps = new Hashtable();
- loggedInFilterProps.put("pattern", ".*\\/api\\/.*");
- loggedInFilterProps.put("contextId", "GossContext");
-
- Hashtable contextWrapperProps = new Hashtable();
- contextWrapperProps.put("contextId", "GossContext");
- contextWrapperProps.put("context.shared", true);
-
- ServiceReferencehttpRef = context.getServiceReference(HttpService.class);
- HttpService httpService = context.getService(httpRef);
-
- if(httpService == null){
- throw new Exception("HttpService not available.");
- }
-
- manager.add(createComponent()
- .setInterface(HttpContext.class.getName(), contextWrapperProps)
- .setImplementation(httpService.createDefaultHttpContext()));
-
- manager.add(createComponent()
- .setInterface(Filter.class.getName(), xDomainProps)
- .setImplementation(XDomainFilter.class));
-
- manager.add(createComponent()
- .setInterface(Filter.class.getName(),loggedInFilterProps)
- .setImplementation(LoggedInFilter.class)
- .add(createServiceDependency()
- .setService(TokenIdentifierMap.class)));
-
- manager.add(createComponent()
- .setInterface(Object.class.getName(), null)
- .setImplementation(LoginService.class)
- //.setCallbacks("added", "removed", null, null)
- .add(createServiceDependency()
- .setService(SecurityManager.class))
- .add(createServiceDependency()
- .setService(TokenIdentifierMap.class)));
-
- manager.add(createComponent()
- .setInterface(Object.class.getName(), null).setImplementation(
- LoginTestService.class));
-
- }
-
- @Override
- public void destroy(BundleContext context, DependencyManager manager)
- throws Exception {
- // noop
- }
-}
-
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/web/Default.java b/pnnl.goss.core/src/pnnl/goss/core/server/web/Default.java
index 0f12816c..f6845e99 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/web/Default.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/web/Default.java
@@ -7,29 +7,29 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.felix.dm.annotation.api.Component;
-import org.apache.felix.dm.annotation.api.Start;
-import org.apache.felix.dm.annotation.api.Stop;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Deactivate;
@Component
-public class Default extends HttpServlet{
-
- private static final long serialVersionUID = -543706852564073624L;
-
- @Start
- public void starting(){
- System.out.println("Startting");
- }
-
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
- // TODO Auto-generated method stub
- super.doGet(req, resp);
- }
-
- @Stop
- public void stopping() {
- System.out.println("Stopping");
- }
+public class Default extends HttpServlet {
+
+ private static final long serialVersionUID = -543706852564073624L;
+
+ @Activate
+ public void starting() {
+ System.out.println("Starting");
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ // TODO Auto-generated method stub
+ super.doGet(req, resp);
+ }
+
+ @Deactivate
+ public void stopping() {
+ System.out.println("Stopping");
+ }
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/web/Hello.java b/pnnl.goss.core/src/pnnl/goss/core/server/web/Hello.java
index 8fd9a7dc..a2fcf39e 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/web/Hello.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/web/Hello.java
@@ -8,29 +8,26 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.apache.felix.dm.annotation.api.Component;
-import org.apache.felix.dm.annotation.api.Property;
-import org.apache.felix.dm.annotation.api.Start;
-import org.apache.felix.dm.annotation.api.Stop;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Deactivate;
-@Component(
- provides = {Servlet.class},
- properties = {@Property(name="alias", value="/hello")})
+@Component(service = Servlet.class, property = {"osgi.http.whiteboard.servlet.pattern=/hello"})
public class Hello extends HttpServlet {
-
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
- resp.getWriter().write("Hello World");
- }
-
- @Start
- public void starting(){
- System.out.println("Starting servlet");
- }
-
- @Stop
- public void stopping(){
- System.out.println("Stopping servilt");
- }
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ resp.getWriter().write("Hello World");
+ }
+
+ @Activate
+ public void starting() {
+ System.out.println("Starting servlet");
+ }
+
+ @Deactivate
+ public void stopping() {
+ System.out.println("Stopping servlet");
+ }
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/web/HelloService.java b/pnnl.goss.core/src/pnnl/goss/core/server/web/HelloService.java
index 3487b662..76491f72 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/web/HelloService.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/web/HelloService.java
@@ -1,48 +1,48 @@
-//package pnnl.goss.core.server.web;
-//
-//import java.util.Dictionary;
-//
-//import javax.servlet.Servlet;
-//import javax.servlet.ServletException;
-//
-//import org.apache.felix.dm.annotation.api.Component;
-//import org.apache.felix.dm.annotation.api.Property;
-//import org.osgi.service.http.HttpContext;
-//import org.osgi.service.http.HttpService;
-//import org.osgi.service.http.NamespaceException;
-//
-//@Component(
-// provides={Servlet.class},
-// properties={@Property(name="alias", value="/hello2")})
-//public class HelloService implements HttpService {
-//
-// @Override
-// public void registerServlet(String alias, Servlet servlet,
-// Dictionary initparams, HttpContext context)
-// throws ServletException, NamespaceException {
-// // TODO Auto-generated method stub
-// System.out.println("Registering servlet");
-// }
-//
-// @Override
-// public void registerResources(String alias, String name, HttpContext context)
-// throws NamespaceException {
-// // TODO Auto-generated method stub
-// System.out.println("Register Resource");
-//
-// }
-//
-// @Override
-// public void unregister(String alias) {
-// // TODO Auto-generated method stub
-// System.out.println("Unregister");
-// }
-//
-// @Override
-// public HttpContext createDefaultHttpContext() {
-// // TODO Auto-generated method stub
-// System.out.println("Create Context!");
-// return null;
-// }
-//
-//}
+// package pnnl.goss.core.server.web;
+//
+// import java.util.Dictionary;
+//
+// import javax.servlet.Servlet;
+// import javax.servlet.ServletException;
+//
+// import org.apache.felix.dm.annotation.api.Component;
+// import org.apache.felix.dm.annotation.api.Property;
+// import org.osgi.service.http.HttpContext;
+// import org.osgi.service.http.HttpService;
+// import org.osgi.service.http.NamespaceException;
+//
+// @Component(
+// provides={Servlet.class},
+// properties={@Property(name="alias", value="/hello2")})
+// public class HelloService implements HttpService {
+//
+// @Override
+// public void registerServlet(String alias, Servlet servlet,
+// Dictionary initparams, HttpContext context)
+// throws ServletException, NamespaceException {
+// // TODO Auto-generated method stub
+// System.out.println("Registering servlet");
+// }
+//
+// @Override
+// public void registerResources(String alias, String name, HttpContext context)
+// throws NamespaceException {
+// // TODO Auto-generated method stub
+// System.out.println("Register Resource");
+//
+// }
+//
+// @Override
+// public void unregister(String alias) {
+// // TODO Auto-generated method stub
+// System.out.println("Unregister");
+// }
+//
+// @Override
+// public HttpContext createDefaultHttpContext() {
+// // TODO Auto-generated method stub
+// System.out.println("Create Context!");
+// return null;
+// }
+//
+// }
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/web/LoggedInFilter.java b/pnnl.goss.core/src/pnnl/goss/core/server/web/LoggedInFilter.java
index d97af755..9c9e0f10 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/web/LoggedInFilter.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/web/LoggedInFilter.java
@@ -22,99 +22,94 @@
import com.google.gson.JsonObject;
/**
- * This filter tests that a user has logged in before allowing
- * access to the requested resource. It does this by using a
- * {@link TokenIdentifierMap} based service that will check the
- * ip address and the pressence of a valid token.
+ * This filter tests that a user has logged in before allowing access to the
+ * requested resource. It does this by using a {@link TokenIdentifierMap} based
+ * service that will check the ip address and the pressence of a valid token.
*
- * If a valid token is present then the request will modified to
- * include an "identifier" parameter that can be used in a web request
- * to authenticate a user's permissions.
+ * If a valid token is present then the request will modified to include an
+ * "identifier" parameter that can be used in a web request to authenticate a
+ * user's permissions.
*
* @author Craig Allwardt
*
*/
-public class LoggedInFilter implements Filter
-{
-
- // Injected by Activator
- private volatile TokenIdentifierMap idMap;
+public class LoggedInFilter implements Filter {
+ // Injected by Activator
+ private volatile TokenIdentifierMap idMap;
@Override
public void init(FilterConfig config)
- throws ServletException
- {
- System.out.println("Initializing filter with config: "+config);
+ throws ServletException {
+ System.out.println("Initializing filter with config: " + config);
}
/**
- * Retrieves a token from the passed request. The token could be
- * in a header if a GET request or in either the header or body
- * of the request if a POST request.
+ * Retrieves a token from the passed request. The token could be in a header if
+ * a GET request or in either the header or body of the request if a POST
+ * request.
*
* @param request
* @return The token or a null string.
*/
- private String getTokenIfPresent(HttpServletRequest request){
-
- String token = request.getHeader("AuthToken");
-
- // Not available through the header
- if (token == null || token.isEmpty()){
-
- // If POST request then check the content of the body for an
- // AuthToken element
- if (request.getMethod().equalsIgnoreCase("POST")){
- StringBuilder body = new StringBuilder();
- char[] charBuffer = new char[128];
- InputStream inputStream;
- try {
- inputStream = request.getInputStream();
- int bytesRead = -1;
- BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
- while ((bytesRead = reader.read(charBuffer)) > 0) {
- body.append(charBuffer, 0, bytesRead);
- }
- } catch (IOException e1) {
- e1.printStackTrace();
- }
-
- if (!body.toString().isEmpty()){
-
- try {
-
- Gson gson = new Gson();
-
- JsonObject json = gson.fromJson(body.toString(), JsonObject.class);
- token = json.get("AuthToken").getAsString();
-
- // Return a null for an empty token string.
- if (token.isEmpty()){
- token = null;
- }
-
-
- }catch (Exception e){
- e.printStackTrace();
- }
- }
- }
- }
-
- return token;
+ private String getTokenIfPresent(HttpServletRequest request) {
+
+ String token = request.getHeader("AuthToken");
+
+ // Not available through the header
+ if (token == null || token.isEmpty()) {
+
+ // If POST request then check the content of the body for an
+ // AuthToken element
+ if (request.getMethod().equalsIgnoreCase("POST")) {
+ StringBuilder body = new StringBuilder();
+ char[] charBuffer = new char[128];
+ InputStream inputStream;
+ try {
+ inputStream = request.getInputStream();
+ int bytesRead = -1;
+ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
+ while ((bytesRead = reader.read(charBuffer)) > 0) {
+ body.append(charBuffer, 0, bytesRead);
+ }
+ } catch (IOException e1) {
+ e1.printStackTrace();
+ }
+
+ if (!body.toString().isEmpty()) {
+
+ try {
+
+ Gson gson = new Gson();
+
+ JsonObject json = gson.fromJson(body.toString(), JsonObject.class);
+ token = json.get("AuthToken").getAsString();
+
+ // Return a null for an empty token string.
+ if (token.isEmpty()) {
+ token = null;
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ return token;
}
/*
- * This function is designed to validate that a user has been logged into
- * the system and made a request within a period of time. The time is
- * not determined in this class but in the {@link TokenIdentifiedMap} service.
- * In addition the token and ip address will be checked to make sure the
- * origin of the request is from the same ip.
+ * This function is designed to validate that a user has been logged into the
+ * system and made a request within a period of time. The time is not determined
+ * in this class but in the {@link TokenIdentifiedMap} service. In addition the
+ * token and ip address will be checked to make sure the origin of the request
+ * is from the same ip.
*
* If the request is a GET request then the header AuthToken must be present
- * with a validated token. If a POST request then the AuthToken can either
- * be present in the header or in a json body element.
+ * with a validated token. If a POST request then the AuthToken can either be
+ * present in the header or in a json body element.
*
* If the AuthToken is valid then an 'identifier' parameter will be set on the
* request before it is sent to the next filter.
@@ -123,41 +118,42 @@ private String getTokenIfPresent(HttpServletRequest request){
* error message is produced.
*
* (non-Javadoc)
- * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
+ *
+ * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
+ * javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
- throws IOException, ServletException
- {
- HttpServletRequest httpReq = (HttpServletRequest) req;
- MultiReadHttpServletRequestWrapper wrapper = new MultiReadHttpServletRequestWrapper(httpReq);
- String authToken = getTokenIfPresent(wrapper);
- String ip = httpReq.getRemoteAddr();
- String identifier = null;
- boolean identifierSet = false;
-
- if (authToken != null){
- identifier = idMap.getIdentifier(ip, authToken);
- if (identifier != null && !identifier.isEmpty()){
- wrapper.setAttribute("identifier", identifier);
- identifierSet = true;
- }
- }
-
- if (!identifierSet){
- ((HttpServletResponse)res).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
- PrintWriter out = res.getWriter();
- out.write("{\"error\":\"Invalid Authentication Token\"}");
- out.close();
- return;
- }
-
- System.out.println("Identifier set: "+identifier);
+ throws IOException, ServletException {
+ HttpServletRequest httpReq = (HttpServletRequest) req;
+ MultiReadHttpServletRequestWrapper wrapper = new MultiReadHttpServletRequestWrapper(httpReq);
+ String authToken = getTokenIfPresent(wrapper);
+ String ip = httpReq.getRemoteAddr();
+ String identifier = null;
+ boolean identifierSet = false;
+
+ if (authToken != null) {
+ identifier = idMap.getIdentifier(ip, authToken);
+ if (identifier != null && !identifier.isEmpty()) {
+ wrapper.setAttribute("identifier", identifier);
+ identifierSet = true;
+ }
+ }
+
+ if (!identifierSet) {
+ ((HttpServletResponse) res).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ PrintWriter out = res.getWriter();
+ out.write("{\"error\":\"Invalid Authentication Token\"}");
+ out.close();
+ return;
+ }
+
+ System.out.println("Identifier set: " + identifier);
chain.doFilter(wrapper, res);
}
- @Override
- public void destroy() {
- System.out.println("Destroying filter.");
- }
+ @Override
+ public void destroy() {
+ System.out.println("Destroying filter.");
+ }
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/web/LoginService.java b/pnnl.goss.core/src/pnnl/goss/core/server/web/LoginService.java
index 18e929dd..e942ee4e 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/web/LoginService.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/web/LoginService.java
@@ -1,12 +1,12 @@
package pnnl.goss.core.server.web;
import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.MediaType;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
@@ -17,33 +17,32 @@
@Path("/login")
public class LoginService {
-
- // Injected from Activator
- private volatile SecurityManager securityManager;
-
- // Injected from Activator.
- private volatile TokenIdentifierMap tokenMap;
-
- public void start(){
- //System.out.println("I AM STARTING!");
- }
-
- @POST
- @Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
- @Produces(MediaType.APPLICATION_JSON)
- public String authenticate(@Context HttpServletRequest request, UsernamePasswordToken params){
- String sessionToken = null;
- try{
- @SuppressWarnings("unused")
- AuthenticationInfo info = securityManager.authenticate(params);
- sessionToken = tokenMap.registerIdentifier(request.getRemoteAddr(), params.getUsername());
-
- } catch(AuthenticationException e){
- return "{\"error\": \"Invalid Login\"}";
- }
-
- return "{\"token\": \"" + sessionToken + "\"}";
- }
-
+
+ // Injected from Activator
+ private volatile SecurityManager securityManager;
+
+ // Injected from Activator.
+ private volatile TokenIdentifierMap tokenMap;
+
+ public void start() {
+ // System.out.println("I AM STARTING!");
+ }
+
+ @POST
+ @Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
+ @Produces(MediaType.APPLICATION_JSON)
+ public String authenticate(@Context HttpServletRequest request, UsernamePasswordToken params) {
+ String sessionToken = null;
+ try {
+ @SuppressWarnings("unused")
+ AuthenticationInfo info = securityManager.authenticate(params);
+ sessionToken = tokenMap.registerIdentifier(request.getRemoteAddr(), params.getUsername());
+
+ } catch (AuthenticationException e) {
+ return "{\"error\": \"Invalid Login\"}";
+ }
+
+ return "{\"token\": \"" + sessionToken + "\"}";
+ }
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/web/LoginTestService.java b/pnnl.goss.core/src/pnnl/goss/core/server/web/LoginTestService.java
index a1585ab6..e8d03891 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/web/LoginTestService.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/web/LoginTestService.java
@@ -1,55 +1,53 @@
package pnnl.goss.core.server.web;
import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.Response.Status;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
@Path("/api")
public class LoginTestService {
-
- @Context
- private HttpServletRequest request;
-
- @POST
- @Path("/echo")
- @Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
- @Produces(MediaType.APPLICATION_JSON)
- public Response runTest(String body){
-
- Gson gson = new Gson();
- JsonObject bodyObj = null;
- JsonObject obj = new JsonObject();
-
- try{
- bodyObj = gson.fromJson(body, JsonObject.class);
- obj.add("data", bodyObj);
- }
- catch(Exception ex){
- obj.addProperty("data", "Non JSON :"+body);
- }
-
- obj.addProperty("Status", "Success");
-
-
- return Response.status(Status.OK).entity(obj.toString()).build();
- }
-
- @POST
- @Path("/loginTest")
- @Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
- @Produces(MediaType.APPLICATION_JSON)
- public String authenticate(@Context HttpServletRequest request){
-
- return "{\"status\": \"Success\"}";
- }
-
+
+ @Context
+ private HttpServletRequest request;
+
+ @POST
+ @Path("/echo")
+ @Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response runTest(String body) {
+
+ Gson gson = new Gson();
+ JsonObject bodyObj = null;
+ JsonObject obj = new JsonObject();
+
+ try {
+ bodyObj = gson.fromJson(body, JsonObject.class);
+ obj.add("data", bodyObj);
+ } catch (Exception ex) {
+ obj.addProperty("data", "Non JSON :" + body);
+ }
+
+ obj.addProperty("Status", "Success");
+
+ return Response.status(Status.OK).entity(obj.toString()).build();
+ }
+
+ @POST
+ @Path("/loginTest")
+ @Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
+ @Produces(MediaType.APPLICATION_JSON)
+ public String authenticate(@Context HttpServletRequest request) {
+
+ return "{\"status\": \"Success\"}";
+ }
+
}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/web/MultiReadHttpServletRequestWrapper.java b/pnnl.goss.core/src/pnnl/goss/core/server/web/MultiReadHttpServletRequestWrapper.java
index 5eb95a2e..fed813b0 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/web/MultiReadHttpServletRequestWrapper.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/web/MultiReadHttpServletRequestWrapper.java
@@ -14,63 +14,61 @@
import org.apache.commons.io.IOUtils;
public class MultiReadHttpServletRequestWrapper extends HttpServletRequestWrapper {
- private ByteArrayOutputStream cachedBytes;
+ private ByteArrayOutputStream cachedBytes;
- public MultiReadHttpServletRequestWrapper(HttpServletRequest request) {
- super(request);
- }
+ public MultiReadHttpServletRequestWrapper(HttpServletRequest request) {
+ super(request);
+ }
- @Override
- public ServletInputStream getInputStream() throws IOException {
- if (cachedBytes == null)
- cacheInputStream();
+ @Override
+ public ServletInputStream getInputStream() throws IOException {
+ if (cachedBytes == null)
+ cacheInputStream();
- return new CachedServletInputStream();
- }
+ return new CachedServletInputStream();
+ }
- @Override
- public BufferedReader getReader() throws IOException{
- return new BufferedReader(new InputStreamReader(getInputStream()));
- }
+ @Override
+ public BufferedReader getReader() throws IOException {
+ return new BufferedReader(new InputStreamReader(getInputStream()));
+ }
- private void cacheInputStream() throws IOException {
- /* Cache the inputstream in order to read it multiple times. For
- * convenience, I use apache.commons IOUtils
- */
- cachedBytes = new ByteArrayOutputStream();
- IOUtils.copy(super.getInputStream(), cachedBytes);
- }
+ private void cacheInputStream() throws IOException {
+ /*
+ * Cache the inputstream in order to read it multiple times. For convenience, I
+ * use apache.commons IOUtils
+ */
+ cachedBytes = new ByteArrayOutputStream();
+ IOUtils.copy(super.getInputStream(), cachedBytes);
+ }
- /* An inputstream which reads the cached request body */
- public class CachedServletInputStream extends ServletInputStream {
- private ByteArrayInputStream input;
+ /* An inputstream which reads the cached request body */
+ public class CachedServletInputStream extends ServletInputStream {
+ private ByteArrayInputStream input;
- public CachedServletInputStream() {
- /* create a new input stream from the cached request body */
- input = new ByteArrayInputStream(cachedBytes.toByteArray());
- }
+ public CachedServletInputStream() {
+ /* create a new input stream from the cached request body */
+ input = new ByteArrayInputStream(cachedBytes.toByteArray());
+ }
- @Override
- public int read() throws IOException {
- return input.read();
- }
+ @Override
+ public int read() throws IOException {
+ return input.read();
+ }
- @Override
- public boolean isFinished() {
- // TODO Auto-generated method stub
- return false;
- }
+ @Override
+ public boolean isFinished() {
+ return input.available() == 0;
+ }
- @Override
- public boolean isReady() {
- // TODO Auto-generated method stub
- return false;
- }
+ @Override
+ public boolean isReady() {
+ return true;
+ }
- @Override
- public void setReadListener(ReadListener arg0) {
- // TODO Auto-generated method stub
-
- }
- }
- }
\ No newline at end of file
+ @Override
+ public void setReadListener(ReadListener readListener) {
+ // Not implemented for this simple wrapper
+ }
+ }
+}
diff --git a/pnnl.goss.core/src/pnnl/goss/core/server/web/XDomainFilter.java b/pnnl.goss.core/src/pnnl/goss/core/server/web/XDomainFilter.java
index 5c146f49..a7fea472 100644
--- a/pnnl.goss.core/src/pnnl/goss/core/server/web/XDomainFilter.java
+++ b/pnnl.goss.core/src/pnnl/goss/core/server/web/XDomainFilter.java
@@ -12,42 +12,42 @@
import javax.servlet.http.HttpServletResponse;
/**
- * This class allows all access to web services from any domain.
- *
+ * This class allows all access to web services from any domain.
+ *
* @author Craig Allwardt
*/
public class XDomainFilter implements Filter {
-
- @Override
- public void destroy() {
-
- }
-
- @Override
- public void doFilter(ServletRequest req, ServletResponse resp,
- FilterChain chain) throws IOException, ServletException {
- HttpServletResponse response = (HttpServletResponse)resp;
- HttpServletRequest request = (HttpServletRequest)req;
-
- response.setHeader("Access-Control-Allow-Origin", "*");
- response.setHeader("Access-Control-Allow-Headers",
- "Origin, X-Requested-With, Content-Type, Accept,AuthToken");
- response.setHeader("Access-Control-Allow-Methods",
- "GET,PUT,POST,DELETE,OPTIONS");
-
- // if its an optionss requrest. we allow it to return successful.
- if (request.getMethod().equalsIgnoreCase("options")){
- response.setStatus(200); // ok
- return;
- }
-
- // Continue on to the next chain.
- chain.doFilter(req, resp);
- }
-
- @Override
- public void init(FilterConfig config) throws ServletException {
- // NOOP
- }
+
+ @Override
+ public void destroy() {
+
+ }
+
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse resp,
+ FilterChain chain) throws IOException, ServletException {
+ HttpServletResponse response = (HttpServletResponse) resp;
+ HttpServletRequest request = (HttpServletRequest) req;
+
+ response.setHeader("Access-Control-Allow-Origin", "*");
+ response.setHeader("Access-Control-Allow-Headers",
+ "Origin, X-Requested-With, Content-Type, Accept,AuthToken");
+ response.setHeader("Access-Control-Allow-Methods",
+ "GET,PUT,POST,DELETE,OPTIONS");
+
+ // if its an optionss requrest. we allow it to return successful.
+ if (request.getMethod().equalsIgnoreCase("options")) {
+ response.setStatus(200); // ok
+ return;
+ }
+
+ // Continue on to the next chain.
+ chain.doFilter(req, resp);
+ }
+
+ @Override
+ public void init(FilterConfig config) throws ServletException {
+ // NOOP
+ }
}
diff --git a/pnnl.goss.core/src/pnnl/goss/server/registry/DataSourceObjectImpl.java b/pnnl.goss.core/src/pnnl/goss/server/registry/DataSourceObjectImpl.java
index c33851d4..91713fbd 100644
--- a/pnnl.goss.core/src/pnnl/goss/server/registry/DataSourceObjectImpl.java
+++ b/pnnl.goss.core/src/pnnl/goss/server/registry/DataSourceObjectImpl.java
@@ -12,50 +12,49 @@
import pnnl.goss.core.server.DataSourceType;
/**
- * An internal (non-service) implementation of DataSourcePooledJdbc interface. This
- * allows the use of the PooledBasicDataSourceBuilderImpl to make use of this class
- * when registering it with the DataSourceRegistry.
- *
+ * An internal (non-service) implementation of DataSourcePooledJdbc interface.
+ * This allows the use of the PooledBasicDataSourceBuilderImpl to make use of
+ * this class when registering it with the DataSourceRegistry.
+ *
* @author Craig Allwardt
*
*/
public class DataSourceObjectImpl implements DataSourcePooledJdbc {
-
- private static final Logger log = LoggerFactory.getLogger(DataSourceObjectImpl.class);
- private String name;
- private DataSourceType datsourceType;
- private DataSource datasource;
-
- /**
- * Construct a new DataSourceObject with the specified name(key), datasourceType and datasource
- *
- * @param name
- * @param dataSourceType
- * @param ds
- */
- public DataSourceObjectImpl(String name, DataSourceType dataSourceType, DataSource ds) {
- this.name = name;
- this.datsourceType = dataSourceType;
- this.datasource = ds;
- log.debug("Created "+DataSourceObjectImpl.class.getName()+ " for ds: "+name);
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public DataSourceType getDataSourceType() {
- // TODO Auto-generated method stub
- return datsourceType;
- }
-
- @Override
- public Connection getConnection() throws SQLException {
- return datasource.getConnection();
- }
-
+ private static final Logger log = LoggerFactory.getLogger(DataSourceObjectImpl.class);
+ private String name;
+ private DataSourceType datsourceType;
+ private DataSource datasource;
+
+ /**
+ * Construct a new DataSourceObject with the specified name(key), datasourceType
+ * and datasource
+ *
+ * @param name
+ * @param dataSourceType
+ * @param ds
+ */
+ public DataSourceObjectImpl(String name, DataSourceType dataSourceType, DataSource ds) {
+ this.name = name;
+ this.datsourceType = dataSourceType;
+ this.datasource = ds;
+ log.debug("Created " + DataSourceObjectImpl.class.getName() + " for ds: " + name);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public DataSourceType getDataSourceType() {
+ // TODO Auto-generated method stub
+ return datsourceType;
+ }
+
+ @Override
+ public Connection getConnection() throws SQLException {
+ return datasource.getConnection();
+ }
}
diff --git a/pnnl.goss.core/src/pnnl/goss/server/registry/DataSourceRegistryImpl.java b/pnnl.goss.core/src/pnnl/goss/server/registry/DataSourceRegistryImpl.java
index 3d165a67..3c9f1b68 100644
--- a/pnnl.goss.core/src/pnnl/goss/server/registry/DataSourceRegistryImpl.java
+++ b/pnnl.goss.core/src/pnnl/goss/server/registry/DataSourceRegistryImpl.java
@@ -4,8 +4,10 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
-import org.apache.felix.dm.annotation.api.Component;
-import org.apache.felix.dm.annotation.api.ServiceDependency;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -15,54 +17,53 @@
import pnnl.goss.core.server.DataSourceRegistry;
import pnnl.goss.core.server.DataSourceType;
-@Component
+@Component(service = DataSourceRegistry.class)
public class DataSourceRegistryImpl implements DataSourceRegistry {
- private static final Logger log = LoggerFactory.getLogger(DataSourceRegistryImpl.class);
+ private static final Logger log = LoggerFactory.getLogger(DataSourceRegistryImpl.class);
- private final Map dataSourceMap = new ConcurrentHashMap<>();
- private final Map, DataSourceObject> serviceRefMap = new ConcurrentHashMap<>();
+ private final Map dataSourceMap = new ConcurrentHashMap<>();
+ private final Map, DataSourceObject> serviceRefMap = new ConcurrentHashMap<>();
- @ServiceDependency(removed="datasourceRemoved", required=false)
- public void datasourceAdded(ServiceReference ref, DataSourceObject obj){
- log.debug("Datasource registered: " + obj.getName());
- dataSourceMap.put(obj.getName(), obj);
- serviceRefMap.put(ref, obj);
- }
+ @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC, unbind = "datasourceRemoved")
+ public void datasourceAdded(ServiceReference ref, DataSourceObject obj) {
+ log.debug("Datasource registered: " + obj.getName());
+ dataSourceMap.put(obj.getName(), obj);
+ serviceRefMap.put(ref, obj);
+ }
- public void datasourceRemoved(ServiceReference ref){
- log.debug("Removing datasource: " + serviceRefMap.get(ref).getName());
- DataSourceObject toRemove = serviceRefMap.remove(ref);
- dataSourceMap.remove(toRemove);
- }
+ public void datasourceRemoved(ServiceReference ref) {
+ log.debug("Removing datasource: " + serviceRefMap.get(ref).getName());
+ DataSourceObject toRemove = serviceRefMap.remove(ref);
+ dataSourceMap.remove(toRemove);
+ }
- @Override
- public DataSourceObject get(String key) {
- DataSourceObject obj = dataSourceMap.get(key);
+ @Override
+ public DataSourceObject get(String key) {
+ DataSourceObject obj = dataSourceMap.get(key);
- return obj;
- }
+ return obj;
+ }
- @Override
- public Map getAvailable() {
- Map map = new HashMap<>();
+ @Override
+ public Map getAvailable() {
+ Map map = new HashMap<>();
- for(DataSourceObject o: dataSourceMap.values()){
- map.put(o.getName(), o.getDataSourceType());
- }
+ for (DataSourceObject o : dataSourceMap.values()) {
+ map.put(o.getName(), o.getDataSourceType());
+ }
- return map;
- }
+ return map;
+ }
- @Override
- public void add(String key, DataSourceObject obj) {
- dataSourceMap.put(key, obj);
- }
-
- @Override
- public void remove(String key) {
- dataSourceMap.remove(key);
- }
+ @Override
+ public void add(String key, DataSourceObject obj) {
+ dataSourceMap.put(key, obj);
+ }
+ @Override
+ public void remove(String key) {
+ dataSourceMap.remove(key);
+ }
}
diff --git a/pnnl.goss.core/src/pnnl/goss/server/registry/HandlerRegistryImpl.java b/pnnl.goss.core/src/pnnl/goss/server/registry/HandlerRegistryImpl.java
index fb8f51dd..2e94d421 100644
--- a/pnnl.goss.core/src/pnnl/goss/server/registry/HandlerRegistryImpl.java
+++ b/pnnl.goss.core/src/pnnl/goss/server/registry/HandlerRegistryImpl.java
@@ -7,8 +7,10 @@
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
-import org.apache.felix.dm.annotation.api.Component;
-import org.apache.felix.dm.annotation.api.ServiceDependency;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
import org.apache.shiro.mgt.SecurityManager;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
@@ -28,222 +30,229 @@
import com.northconcepts.exception.SystemException;
-@Component
+@Component(service = RequestHandlerRegistry.class)
public class HandlerRegistryImpl implements RequestHandlerRegistry {
- private static final Logger log = LoggerFactory.getLogger(HandlerRegistryImpl.class);
-
- // Keep track of the service references so that when they go away we can clean up the list.
- private final Map, RequestHandler> registeredHandlers = new ConcurrentHashMap<>();
- private final Map, AuthorizationHandler> authorizationHandlers = new ConcurrentHashMap<>();
- private final Map, RequestUploadHandler> registeredUploadHandlers = new ConcurrentHashMap<>();
-
- @ServiceDependency
- private volatile SecurityManager securityManager;
-
- @ServiceDependency
- private volatile PermissionAdapter permissionAdapter;
-
- // Map
- private final Map uploadHandlers = new ConcurrentHashMap<>();
-
- // HandlerMapping now takes care of the mapping of requests through to authorization class name.
- // The actual instances are then looked up in the authorizationInstanceMap.
- private final Map handlerMapping = new ConcurrentHashMap<>();
- private final Map authorizationInstanceMap = new ConcurrentHashMap<>();
-
- private class UploadHandlerMapping{
- private volatile String uploadDataType;
- private volatile String authorizationHandlerClassName;
- private volatile RequestUploadHandler uploadRequestHandlerInstance;
-
- @SuppressWarnings("unused")
- public String getUploadDataType() {
- return uploadDataType;
- }
- public UploadHandlerMapping setDataType(String uploadDataType) {
- this.uploadDataType = uploadDataType;
- return this;
- }
- public String getAuthorizationHandlerClassName() {
- return authorizationHandlerClassName;
- }
- public UploadHandlerMapping setAuthorizationHandlerClassName(
- String authorizationHandlerClassName) {
- this.authorizationHandlerClassName = authorizationHandlerClassName;
- return this;
- }
- public RequestUploadHandler getRequestHandlerInstance() {
- return uploadRequestHandlerInstance;
- }
- public UploadHandlerMapping setRequestHandlerInstance(RequestUploadHandler uploadRequestHandlerInstance) {
- this.uploadRequestHandlerInstance = uploadRequestHandlerInstance;
- return this;
- }
- }
-
- private class HandlerMapping{
- private volatile String requestClassName;
- private volatile String authorizationHandlerClassName;
- private volatile RequestHandler requestHandlerInstance;
-
- @SuppressWarnings("unused")
- public String getRequestClassName() {
- return requestClassName;
- }
- public HandlerMapping setRequestClassName(String requestClassName) {
- this.requestClassName = requestClassName;
- return this;
- }
- @SuppressWarnings("unused")
- public String getAuthorizationHandlerClassName() {
- return authorizationHandlerClassName;
- }
- public HandlerMapping setAuthorizationHandlerClassName(
- String authorizationHandlerClassName) {
- this.authorizationHandlerClassName = authorizationHandlerClassName;
- return this;
- }
- public RequestHandler getRequestHandlerInstance() {
- return requestHandlerInstance;
- }
- public HandlerMapping setRequestHandlerInstance(RequestHandler requestHandlerInstance) {
- this.requestHandlerInstance = requestHandlerInstance;
- return this;
- }
- }
-
-
- @ServiceDependency(removed="authorizationHandlerRemoved", required=false)
- public void authorizationHandlerAdded(ServiceReference ref, AuthorizationHandler handler){
- System.out.println("Registering Authorization Handler: "+handler.getClass().getName());
- authorizationHandlers.put(ref, handler);
- authorizationInstanceMap.put(handler.getClass().getName(), handler);
- }
-
- public void authorizationHandlerRemoved(ServiceReference ref){
-
- AuthorizationHandler handler = authorizationHandlers.remove(ref);
- System.out.println("Un-Registering Authorization Handler: "+handler.getClass().getName());
- authorizationInstanceMap.remove(handler.getClass().getName());
- }
-
- @ServiceDependency(removed="requestHandlerRemoved", required=false)
- public void requestHandlerAdded(ServiceReference ref, RequestHandler handler){
- System.out.println("Registering Request Handler: "+handler.getClass().getName());
- registeredHandlers.put(ref, handler);
- handler.getHandles().forEach((k, v)->{
- handlerMapping.put(k.getName(), new HandlerMapping()
- .setRequestClassName(k.getName())
- .setRequestHandlerInstance(handler)
- .setAuthorizationHandlerClassName(v.getName()));
- });
- }
-
- public void requestHandlerRemoved(ServiceReference ref){
-
- RequestHandler handler = registeredHandlers.remove(ref);
- System.out.println("Un-Registering Request Handler: "+ handler.getClass().getName());
- handler.getHandles().forEach((k,v)->{
- handlerMapping.remove(k);
- });
- registeredHandlers.remove(ref);
- }
-
-
- @ServiceDependency(removed="uploadHandlerRemoved", required=false)
- public void uploadHandlerAdded(ServiceReference ref, RequestUploadHandler uploadHandler){
- System.out.println("Registering Upload Handler: "+uploadHandler.getClass().getName());
- registeredUploadHandlers.put(ref, uploadHandler);
- uploadHandler.getHandlerDataTypes().forEach((k, v)-> {
- uploadHandlers.put(k, new UploadHandlerMapping()
- .setDataType(k)
- .setAuthorizationHandlerClassName(v.getName())
- .setRequestHandlerInstance(uploadHandler));
- });
- }
-
- public void uploadHandlerRemoved(ServiceReference ref){
- RequestUploadHandler handler = registeredUploadHandlers.remove(ref);
- System.out.println("Un-Registering Upload Handler: "+handler.getClass().getName());
- handler.getHandlerDataTypes().forEach((k,v)->{
- uploadHandlers.remove(k);
- });
- uploadHandlers.remove(handler.getClass().getName());
- }
-
-
- @Override
- public RequestHandler getHandler(Class extends Request> request) throws HandlerNotFoundException {
- log.debug("getHandler for class: "+request.getName());
- Optional maybeHandler = Optional.ofNullable(
- handlerMapping.get(request.getName()).getRequestHandlerInstance());
- return maybeHandler.orElseThrow(()-> new HandlerNotFoundException(request));
-
- }
-
- @Override
- public List list() {
- ArrayList items = new ArrayList<>();
- registeredHandlers.values().forEach(p->items.add(p));
- registeredUploadHandlers.values().forEach(p->items.add(p));
- authorizationHandlers.values().forEach(p->items.add(p));
-
- return items;
- }
-
- @Override
- public Response handle(Request request) throws HandlerNotFoundException {
-
- RequestHandler handler = getHandler(request.getClass());
- return handler.handle(request);
-
- }
-
- @Override
- public Response handle(String dataType, Serializable data) throws HandlerNotFoundException {
- log.debug("handling datatype: "+ dataType);
- RequestUploadHandler handler = Optional
- .ofNullable(uploadHandlers.get(dataType).getRequestHandlerInstance())
- .orElseThrow(()-> new HandlerNotFoundException(dataType));
- return handler.upload(dataType, data);
- }
-
- @Override
- public Response handle(RequestAsync request) throws HandlerNotFoundException {
- log.debug("handling async request:");
- RequestHandler handler = getHandler(request.getClass());
- return handler.handle(request);
- }
-
- @Override
- public RequestUploadHandler getUploadHandler(String dataType)
- throws HandlerNotFoundException {
- return uploadHandlers.get(dataType).getRequestHandlerInstance();
- }
-
- @Override
- public boolean checkAccess(Request request, String identifier)
- throws SystemException {
-
- AuthorizationHandler authHandler = null;
- log.debug("Checking access for request " + request.getClass() + " identifier " + identifier);
- if (request instanceof UploadRequest){
- // Upload request handling.
- log.debug("Handle auth request for upload!");
- UploadRequest upRquest = (UploadRequest)request;
- UploadHandlerMapping mapTo = uploadHandlers.get(upRquest.getDataType());
- authHandler = authorizationInstanceMap.get(mapTo.getAuthorizationHandlerClassName());
- }
- else {
- HandlerMapping requestToHandlerMapping = handlerMapping.get(request.getClass().getName());
- authHandler = authorizationInstanceMap.get(requestToHandlerMapping.authorizationHandlerClassName);
- }
-
- if (authHandler == null){
- return false;
- }
- return authHandler.isAuthorized(request, permissionAdapter.getPermissions(identifier));
- }
-
-
+ private static final Logger log = LoggerFactory.getLogger(HandlerRegistryImpl.class);
+
+ // Keep track of the service references so that when they go away we can clean
+ // up the list.
+ private final Map, RequestHandler> registeredHandlers = new ConcurrentHashMap<>();
+ private final Map, AuthorizationHandler> authorizationHandlers = new ConcurrentHashMap<>();
+ private final Map, RequestUploadHandler> registeredUploadHandlers = new ConcurrentHashMap<>();
+
+ @Reference
+ private volatile SecurityManager securityManager;
+
+ @Reference
+ private volatile PermissionAdapter permissionAdapter;
+
+ // Map
+ private final Map uploadHandlers = new ConcurrentHashMap<>();
+
+ // HandlerMapping now takes care of the mapping of requests through to
+ // authorization class name.
+ // The actual instances are then looked up in the authorizationInstanceMap.
+ private final Map handlerMapping = new ConcurrentHashMap<>();
+ private final Map authorizationInstanceMap = new ConcurrentHashMap<>();
+
+ private class UploadHandlerMapping {
+ private volatile String uploadDataType;
+ private volatile String authorizationHandlerClassName;
+ private volatile RequestUploadHandler uploadRequestHandlerInstance;
+
+ @SuppressWarnings("unused")
+ public String getUploadDataType() {
+ return uploadDataType;
+ }
+
+ public UploadHandlerMapping setDataType(String uploadDataType) {
+ this.uploadDataType = uploadDataType;
+ return this;
+ }
+
+ public String getAuthorizationHandlerClassName() {
+ return authorizationHandlerClassName;
+ }
+
+ public UploadHandlerMapping setAuthorizationHandlerClassName(
+ String authorizationHandlerClassName) {
+ this.authorizationHandlerClassName = authorizationHandlerClassName;
+ return this;
+ }
+
+ public RequestUploadHandler getRequestHandlerInstance() {
+ return uploadRequestHandlerInstance;
+ }
+
+ public UploadHandlerMapping setRequestHandlerInstance(RequestUploadHandler uploadRequestHandlerInstance) {
+ this.uploadRequestHandlerInstance = uploadRequestHandlerInstance;
+ return this;
+ }
+ }
+
+ private class HandlerMapping {
+ private volatile String requestClassName;
+ private volatile String authorizationHandlerClassName;
+ private volatile RequestHandler requestHandlerInstance;
+
+ @SuppressWarnings("unused")
+ public String getRequestClassName() {
+ return requestClassName;
+ }
+
+ public HandlerMapping setRequestClassName(String requestClassName) {
+ this.requestClassName = requestClassName;
+ return this;
+ }
+
+ @SuppressWarnings("unused")
+ public String getAuthorizationHandlerClassName() {
+ return authorizationHandlerClassName;
+ }
+
+ public HandlerMapping setAuthorizationHandlerClassName(
+ String authorizationHandlerClassName) {
+ this.authorizationHandlerClassName = authorizationHandlerClassName;
+ return this;
+ }
+
+ public RequestHandler getRequestHandlerInstance() {
+ return requestHandlerInstance;
+ }
+
+ public HandlerMapping setRequestHandlerInstance(RequestHandler requestHandlerInstance) {
+ this.requestHandlerInstance = requestHandlerInstance;
+ return this;
+ }
+ }
+
+ @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC, unbind = "authorizationHandlerRemoved")
+ public void authorizationHandlerAdded(ServiceReference ref, AuthorizationHandler handler) {
+ System.out.println("Registering Authorization Handler: " + handler.getClass().getName());
+ authorizationHandlers.put(ref, handler);
+ authorizationInstanceMap.put(handler.getClass().getName(), handler);
+ }
+
+ public void authorizationHandlerRemoved(ServiceReference ref) {
+
+ AuthorizationHandler handler = authorizationHandlers.remove(ref);
+ System.out.println("Un-Registering Authorization Handler: " + handler.getClass().getName());
+ authorizationInstanceMap.remove(handler.getClass().getName());
+ }
+
+ @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC, unbind = "requestHandlerRemoved")
+ public void requestHandlerAdded(ServiceReference ref, RequestHandler handler) {
+ System.out.println("Registering Request Handler: " + handler.getClass().getName());
+ registeredHandlers.put(ref, handler);
+ handler.getHandles().forEach((k, v) -> {
+ handlerMapping.put(k.getName(), new HandlerMapping()
+ .setRequestClassName(k.getName())
+ .setRequestHandlerInstance(handler)
+ .setAuthorizationHandlerClassName(v.getName()));
+ });
+ }
+
+ public void requestHandlerRemoved(ServiceReference ref) {
+
+ RequestHandler handler = registeredHandlers.remove(ref);
+ System.out.println("Un-Registering Request Handler: " + handler.getClass().getName());
+ handler.getHandles().forEach((k, v) -> {
+ handlerMapping.remove(k);
+ });
+ registeredHandlers.remove(ref);
+ }
+
+ @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC, unbind = "uploadHandlerRemoved")
+ public void uploadHandlerAdded(ServiceReference ref, RequestUploadHandler uploadHandler) {
+ System.out.println("Registering Upload Handler: " + uploadHandler.getClass().getName());
+ registeredUploadHandlers.put(ref, uploadHandler);
+ uploadHandler.getHandlerDataTypes().forEach((k, v) -> {
+ uploadHandlers.put(k, new UploadHandlerMapping()
+ .setDataType(k)
+ .setAuthorizationHandlerClassName(v.getName())
+ .setRequestHandlerInstance(uploadHandler));
+ });
+ }
+
+ public void uploadHandlerRemoved(ServiceReference ref) {
+ RequestUploadHandler handler = registeredUploadHandlers.remove(ref);
+ System.out.println("Un-Registering Upload Handler: " + handler.getClass().getName());
+ handler.getHandlerDataTypes().forEach((k, v) -> {
+ uploadHandlers.remove(k);
+ });
+ uploadHandlers.remove(handler.getClass().getName());
+ }
+
+ @Override
+ public RequestHandler getHandler(Class extends Request> request) throws HandlerNotFoundException {
+ log.debug("getHandler for class: " + request.getName());
+ Optional maybeHandler = Optional.ofNullable(
+ handlerMapping.get(request.getName()).getRequestHandlerInstance());
+ return maybeHandler.orElseThrow(() -> new HandlerNotFoundException(request));
+
+ }
+
+ @Override
+ public List list() {
+ ArrayList items = new ArrayList<>();
+ registeredHandlers.values().forEach(p -> items.add(p));
+ registeredUploadHandlers.values().forEach(p -> items.add(p));
+ authorizationHandlers.values().forEach(p -> items.add(p));
+
+ return items;
+ }
+
+ @Override
+ public Response handle(Request request) throws HandlerNotFoundException {
+
+ RequestHandler handler = getHandler(request.getClass());
+ return handler.handle(request);
+
+ }
+
+ @Override
+ public Response handle(String dataType, Serializable data) throws HandlerNotFoundException {
+ log.debug("handling datatype: " + dataType);
+ RequestUploadHandler handler = Optional
+ .ofNullable(uploadHandlers.get(dataType).getRequestHandlerInstance())
+ .orElseThrow(() -> new HandlerNotFoundException(dataType));
+ return handler.upload(dataType, data);
+ }
+
+ @Override
+ public Response handle(RequestAsync request) throws HandlerNotFoundException {
+ log.debug("handling async request:");
+ RequestHandler handler = getHandler(request.getClass());
+ return handler.handle(request);
+ }
+
+ @Override
+ public RequestUploadHandler getUploadHandler(String dataType)
+ throws HandlerNotFoundException {
+ return uploadHandlers.get(dataType).getRequestHandlerInstance();
+ }
+
+ @Override
+ public boolean checkAccess(Request request, String identifier)
+ throws SystemException {
+
+ AuthorizationHandler authHandler = null;
+ log.debug("Checking access for request " + request.getClass() + " identifier " + identifier);
+ if (request instanceof UploadRequest) {
+ // Upload request handling.
+ log.debug("Handle auth request for upload!");
+ UploadRequest upRquest = (UploadRequest) request;
+ UploadHandlerMapping mapTo = uploadHandlers.get(upRquest.getDataType());
+ authHandler = authorizationInstanceMap.get(mapTo.getAuthorizationHandlerClassName());
+ } else {
+ HandlerMapping requestToHandlerMapping = handlerMapping.get(request.getClass().getName());
+ authHandler = authorizationInstanceMap.get(requestToHandlerMapping.authorizationHandlerClassName);
+ }
+
+ if (authHandler == null) {
+ return false;
+ }
+ return authHandler.isAuthorized(request, permissionAdapter.getPermissions(identifier));
+ }
+
}
diff --git a/pnnl.goss.core/src/pnnl/goss/server/registry/PooledBasicDataSourceBuilderImpl.java b/pnnl.goss.core/src/pnnl/goss/server/registry/PooledBasicDataSourceBuilderImpl.java
index c20b301f..e5d82695 100644
--- a/pnnl.goss.core/src/pnnl/goss/server/registry/PooledBasicDataSourceBuilderImpl.java
+++ b/pnnl.goss.core/src/pnnl/goss/server/registry/PooledBasicDataSourceBuilderImpl.java
@@ -7,8 +7,8 @@
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
-import org.apache.felix.dm.annotation.api.Component;
-import org.apache.felix.dm.annotation.api.ServiceDependency;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -17,70 +17,69 @@
import pnnl.goss.core.server.DataSourceType;
/**
- * The PooledBasicDataSourceBuilderImpl class implements the DataSourceBuilder inteface. It
- * creates a DataSourceObject wrapper so that one can easily register datasources without
- * having to create another class.
- *
- * The easiest way to do this would be during the loading of a component, either in the
- * service Activator or in the @Start annotated method if using dependencymanager.
- *
+ * The PooledBasicDataSourceBuilderImpl class implements the DataSourceBuilder
+ * inteface. It creates a DataSourceObject wrapper so that one can easily
+ * register datasources without having to create another class.
+ *
+ * The easiest way to do this would be during the loading of a component, either
+ * in the service Activator or in the @Start annotated method if using
+ * dependencymanager.
+ *
* @author Craig Allwardt
*
*/
-@Component
+@Component(service = DataSourceBuilder.class)
public class PooledBasicDataSourceBuilderImpl implements DataSourceBuilder {
-
- @ServiceDependency
- private DataSourceRegistry registry;
-
- private static final Logger log = LoggerFactory.getLogger(PooledBasicDataSourceBuilderImpl.class);
-
-
- public void createMysql(String dsName, String url, String username, String password) throws Exception{
- create(dsName, url, username, password, "com.mysql.jdbc.Driver");
- }
-
- @Override
- public void create(String dsName, String url, String username, String password,
- String driver) throws Exception {
-
- Properties propertiesForDataSource = new Properties();
- propertiesForDataSource.setProperty("username", username);
- propertiesForDataSource.setProperty("password", password);
- propertiesForDataSource.setProperty("url", url);
- propertiesForDataSource.setProperty("driverClassName", driver);
-
- create(dsName, propertiesForDataSource);
- }
-
- @Override
- public void create(String dsName, Properties properties) throws Exception {
-
- List checkItems = Arrays.asList(new String[]{"username", "password", "url", "driverClassName"});
-
- for (String item: checkItems){
- if(properties.containsKey(item)){
- String value = properties.getProperty(item);
- if (value == null || value.isEmpty()){
- throw new IllegalArgumentException(item + " was specified incorrectly!");
- }
- }
- else{
- throw new IllegalArgumentException(item+" must be specified!");
- }
- }
-
- if (!properties.containsKey("maxOpenPreparedStatements")){
- properties.setProperty("maxOpenPreparedStatements", "10");
- }
-
- log.debug("Creating BasicDataSource\n\tURI:"+properties.getProperty("url")+"\n\tUser:\n\t"+properties.getProperty("username"));
-
- Class.forName(properties.getProperty("driverClassName"));
-
- DataSource ds = BasicDataSourceFactory.createDataSource(properties);
-
-
- registry.add(dsName, new DataSourceObjectImpl(dsName, DataSourceType.DS_TYPE_JDBC, ds));
- }
+
+ @Reference
+ private DataSourceRegistry registry;
+
+ private static final Logger log = LoggerFactory.getLogger(PooledBasicDataSourceBuilderImpl.class);
+
+ public void createMysql(String dsName, String url, String username, String password) throws Exception {
+ create(dsName, url, username, password, "com.mysql.jdbc.Driver");
+ }
+
+ @Override
+ public void create(String dsName, String url, String username, String password,
+ String driver) throws Exception {
+
+ Properties propertiesForDataSource = new Properties();
+ propertiesForDataSource.setProperty("username", username);
+ propertiesForDataSource.setProperty("password", password);
+ propertiesForDataSource.setProperty("url", url);
+ propertiesForDataSource.setProperty("driverClassName", driver);
+
+ create(dsName, propertiesForDataSource);
+ }
+
+ @Override
+ public void create(String dsName, Properties properties) throws Exception {
+
+ List checkItems = Arrays.asList(new String[]{"username", "password", "url", "driverClassName"});
+
+ for (String item : checkItems) {
+ if (properties.containsKey(item)) {
+ String value = properties.getProperty(item);
+ if (value == null || value.isEmpty()) {
+ throw new IllegalArgumentException(item + " was specified incorrectly!");
+ }
+ } else {
+ throw new IllegalArgumentException(item + " must be specified!");
+ }
+ }
+
+ if (!properties.containsKey("maxOpenPreparedStatements")) {
+ properties.setProperty("maxOpenPreparedStatements", "10");
+ }
+
+ log.debug("Creating BasicDataSource\n\tURI:" + properties.getProperty("url") + "\n\tUser:\n\t"
+ + properties.getProperty("username"));
+
+ Class.forName(properties.getProperty("driverClassName"));
+
+ DataSource ds = BasicDataSourceFactory.createDataSource(properties);
+
+ registry.add(dsName, new DataSourceObjectImpl(dsName, DataSourceType.DS_TYPE_JDBC, ds));
+ }
}
diff --git a/pnnl.goss.core/test/pnnl/goss/core/client/test/DestinationTypeTest.java b/pnnl.goss.core/test/pnnl/goss/core/client/test/DestinationTypeTest.java
new file mode 100644
index 00000000..eb534269
--- /dev/null
+++ b/pnnl.goss.core/test/pnnl/goss/core/client/test/DestinationTypeTest.java
@@ -0,0 +1,104 @@
+package pnnl.goss.core.client.test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import pnnl.goss.core.Client.DESTINATION_TYPE;
+
+/**
+ * Tests for the DESTINATION_TYPE enum and queue/topic support in the GOSS
+ * client.
+ *
+ * The Java GOSS client now supports both QUEUE and TOPIC destination types,
+ * matching the Python client's behavior.
+ *
+ * Key differences between Queue and Topic: - QUEUE: Point-to-point messaging.
+ * Each message is consumed by exactly one consumer. This is the default for
+ * getResponse() to match Python client behavior. - TOPIC: Publish-subscribe
+ * messaging. Each message is delivered to all subscribers. This is the default
+ * for subscribe() as topics are typically used for broadcast events.
+ *
+ * Usage examples:
+ *
+ * // Subscribe to a queue (for request/response patterns)
+ * client.subscribe("goss.gridappsd.process.request", handler,
+ * DESTINATION_TYPE.QUEUE);
+ *
+ * // Subscribe to a topic (for broadcast events)
+ * client.subscribe("goss.gridappsd.simulation.output.123", handler,
+ * DESTINATION_TYPE.TOPIC);
+ *
+ * // Publish to a queue client.publish("goss.gridappsd.process.request",
+ * message, DESTINATION_TYPE.QUEUE);
+ *
+ * // Publish to a topic client.publish("goss.gridappsd.platform.log", message,
+ * DESTINATION_TYPE.TOPIC);
+ *
+ * // Send request and get response (defaults to QUEUE)
+ * client.getResponse(request, "goss.gridappsd.process.request",
+ * RESPONSE_FORMAT.JSON);
+ *
+ * // Send request with explicit destination type client.getResponse(request,
+ * "my.topic", RESPONSE_FORMAT.JSON, DESTINATION_TYPE.TOPIC);
+ */
+public class DestinationTypeTest {
+
+ @Test
+ @DisplayName("DESTINATION_TYPE enum should have QUEUE and TOPIC values")
+ public void destinationTypeHasQueueAndTopic() {
+ // Verify enum values exist
+ assertThat(DESTINATION_TYPE.values()).hasSize(2);
+ assertThat(DESTINATION_TYPE.valueOf("QUEUE")).isEqualTo(DESTINATION_TYPE.QUEUE);
+ assertThat(DESTINATION_TYPE.valueOf("TOPIC")).isEqualTo(DESTINATION_TYPE.TOPIC);
+ }
+
+ @Test
+ @DisplayName("QUEUE should be the preferred type for request/response patterns")
+ public void queueIsPreferredForRequestResponse() {
+ // Document that QUEUE is recommended for request/response
+ // This matches Python client behavior where get_response uses /queue/
+ // prefix
+ DESTINATION_TYPE requestResponseType = DESTINATION_TYPE.QUEUE;
+
+ assertThat(requestResponseType)
+ .as("Request/response patterns should use QUEUE for point-to-point delivery")
+ .isEqualTo(DESTINATION_TYPE.QUEUE);
+ }
+
+ @Test
+ @DisplayName("TOPIC should be used for broadcast/event patterns")
+ public void topicIsPreferredForBroadcast() {
+ // Document that TOPIC is recommended for events/broadcasts
+ DESTINATION_TYPE broadcastType = DESTINATION_TYPE.TOPIC;
+
+ assertThat(broadcastType)
+ .as("Broadcast patterns should use TOPIC for pub/sub delivery")
+ .isEqualTo(DESTINATION_TYPE.TOPIC);
+ }
+
+ @Test
+ @DisplayName("Enum ordinal values should be stable")
+ public void enumOrdinalsAreStable() {
+ // Verify ordinal values for serialization stability
+ assertThat(DESTINATION_TYPE.TOPIC.ordinal()).isEqualTo(0);
+ assertThat(DESTINATION_TYPE.QUEUE.ordinal()).isEqualTo(1);
+ }
+
+ @Test
+ @DisplayName("Enum should support standard operations")
+ public void enumSupportsStandardOperations() {
+ // Test enum operations
+ assertThat(DESTINATION_TYPE.QUEUE.name()).isEqualTo("QUEUE");
+ assertThat(DESTINATION_TYPE.TOPIC.name()).isEqualTo("TOPIC");
+
+ // Test comparison
+ assertThat(DESTINATION_TYPE.QUEUE).isNotEqualTo(DESTINATION_TYPE.TOPIC);
+
+ // Test valueOf round-trip
+ for (DESTINATION_TYPE type : DESTINATION_TYPE.values()) {
+ assertThat(DESTINATION_TYPE.valueOf(type.name())).isEqualTo(type);
+ }
+ }
+}
diff --git a/pnnl.goss.core/test/pnnl/goss/core/server/impl/test/HandlerRegistryImplTest.java b/pnnl.goss.core/test/pnnl/goss/core/server/impl/test/HandlerRegistryImplTest.java
index 32de4802..cc69eb59 100644
--- a/pnnl.goss.core/test/pnnl/goss/core/server/impl/test/HandlerRegistryImplTest.java
+++ b/pnnl.goss.core/test/pnnl/goss/core/server/impl/test/HandlerRegistryImplTest.java
@@ -1,6 +1,9 @@
package pnnl.goss.core.server.impl.test;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.fail;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.Mockito.mock;
import java.io.Serializable;
@@ -8,8 +11,9 @@
import java.util.Map;
import java.util.Set;
-import org.junit.Before;
-import org.junit.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
import org.osgi.framework.ServiceReference;
import pnnl.goss.core.Request;
@@ -21,105 +25,125 @@
import pnnl.goss.core.server.RequestUploadHandler;
import pnnl.goss.server.registry.HandlerRegistryImpl;
-
public class HandlerRegistryImplTest {
-
- private HandlerRegistryImpl registry;
-
- private class MyRequest extends Request{
-
- private static final long serialVersionUID = 402798455538154736L;
-
- }
-
- private class MyUploadRequest extends UploadRequest{
-
- private static final long serialVersionUID = 4027984612538154736L;
-
- public MyUploadRequest(Serializable data, String dataType) {
- super(data, dataType);
- }
-
- }
-
- private class MyAuthorizationHandler implements AuthorizationHandler{
-
- @Override
- public boolean isAuthorized(Request request, Set userRoles) {
- return false;
- }
-
- }
- private class MyUploadHandler implements RequestUploadHandler{
-
- @Override
- public Map> getHandlerDataTypes() {
- Map> list = new HashMap<>();
- list.put(MyUploadRequest.class.getName(), MyAuthorizationHandler.class);
- return list;
- }
-
- @Override
- public Response upload(String dataType, Serializable data) {
- // TODO Auto-generated method stub
- return null;
- }
-
- }
-
- private class MyRequestHandler implements RequestHandler{
-
- @Override
- public Map, Class extends AuthorizationHandler>> getHandles() {
- Map, Class extends AuthorizationHandler>> list = new HashMap<>();
- list.put(MyRequest.class, MyAuthorizationHandler.class);
- return list;
-
- }
-
- @Override
- public Response handle(Request request) {
- // TODO Auto-generated method stub
- return null;
- }
-
- }
-
- @Before
- public void before(){
- registry = new HandlerRegistryImpl();
- }
-
- @Test
- public void canAddAndGetUploadHandler(){
- @SuppressWarnings("unchecked")
- ServiceReference ref = (ServiceReference)mock(ServiceReference.class);
- RequestUploadHandler handler = new MyUploadHandler();
- registry.uploadHandlerAdded(ref, handler);
- try {
- RequestUploadHandler backHandler = registry.getUploadHandler(MyUploadRequest.class.getName());
- assertSame(handler, (RequestUploadHandler)backHandler);
- } catch (HandlerNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- fail();
- }
- }
-
- @Test
- public void canAddAndGetRequestHandler(){
- @SuppressWarnings("unchecked")
- ServiceReference ref = (ServiceReference)mock(ServiceReference.class);
- RequestHandler handler = new MyRequestHandler();
- registry.requestHandlerAdded(ref, handler);
- try {
- RequestHandler backHandler = registry.getHandler(MyRequest.class);
- assertSame(handler, (RequestHandler)backHandler);
- } catch (HandlerNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- fail();
- }
- }
+
+ private HandlerRegistryImpl registry;
+
+ private class MyRequest extends Request {
+
+ private static final long serialVersionUID = 402798455538154736L;
+
+ }
+
+ private class MyUploadRequest extends UploadRequest {
+
+ private static final long serialVersionUID = 4027984612538154736L;
+
+ public MyUploadRequest(Serializable data, String dataType) {
+ super(data, dataType);
+ }
+
+ }
+
+ private class MyAuthorizationHandler implements AuthorizationHandler {
+
+ @Override
+ public boolean isAuthorized(Request request, Set userRoles) {
+ return false;
+ }
+
+ }
+
+ private class MyUploadHandler implements RequestUploadHandler {
+
+ @Override
+ public Map> getHandlerDataTypes() {
+ Map> list = new HashMap<>();
+ list.put(MyUploadRequest.class.getName(), MyAuthorizationHandler.class);
+ return list;
+ }
+
+ @Override
+ public Response upload(String dataType, Serializable data) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ }
+
+ private class MyRequestHandler implements RequestHandler {
+
+ @Override
+ public Map, Class extends AuthorizationHandler>> getHandles() {
+ Map, Class extends AuthorizationHandler>> list = new HashMap<>();
+ list.put(MyRequest.class, MyAuthorizationHandler.class);
+ return list;
+
+ }
+
+ @Override
+ public Response handle(Request request) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ }
+
+ @BeforeEach
+ public void setUp() {
+ registry = new HandlerRegistryImpl();
+ }
+
+ @Test
+ @DisplayName("Should successfully add and retrieve upload handler")
+ public void canAddAndGetUploadHandler() {
+ // Given
+ @SuppressWarnings("unchecked")
+ ServiceReference ref = mock(ServiceReference.class);
+ RequestUploadHandler handler = new MyUploadHandler();
+
+ // When
+ registry.uploadHandlerAdded(ref, handler);
+
+ // Then
+ assertDoesNotThrow(() -> {
+ RequestUploadHandler backHandler = registry.getUploadHandler(MyUploadRequest.class.getName());
+ assertSame(handler, backHandler);
+ assertThat(backHandler).isNotNull().isEqualTo(handler);
+ });
+ }
+
+ @Test
+ @DisplayName("Should successfully add and retrieve request handler")
+ public void canAddAndGetRequestHandler() {
+ // Given
+ @SuppressWarnings("unchecked")
+ ServiceReference ref = mock(ServiceReference.class);
+ RequestHandler handler = new MyRequestHandler();
+
+ // When
+ registry.requestHandlerAdded(ref, handler);
+
+ // Then
+ assertDoesNotThrow(() -> {
+ RequestHandler backHandler = registry.getHandler(MyRequest.class);
+ assertSame(handler, backHandler);
+ assertThat(backHandler).isNotNull().isEqualTo(handler);
+ });
+ }
+
+ @Test
+ @DisplayName("Should throw exception when handler not found")
+ public void shouldThrowExceptionWhenHandlerNotFound() {
+ // Given an empty registry
+
+ // Then - the implementation has a bug that throws NullPointerException instead
+ // This test documents the actual behavior
+ assertThatThrownBy(() -> registry.getHandler(MyRequest.class))
+ .isInstanceOf(NullPointerException.class);
+
+ assertThatThrownBy(() -> registry.getUploadHandler("NonExistent"))
+ .isInstanceOf(NullPointerException.class);
+ }
}
diff --git a/push-to-local-goss-repository.py b/push-to-local-goss-repository.py
new file mode 100755
index 00000000..fe950635
--- /dev/null
+++ b/push-to-local-goss-repository.py
@@ -0,0 +1,287 @@
+#!/usr/bin/env python3
+"""
+Push GOSS artifacts to GOSS-Repository
+Copies JARs from build output to the specified GOSS-Repository (release or snapshot)
+"""
+
+import argparse
+import hashlib
+import os
+import re
+import shutil
+import subprocess
+import sys
+import zipfile
+from pathlib import Path
+
+
+# ANSI Colors
+class Colors:
+ RED = '\033[0;31m'
+ GREEN = '\033[0;32m'
+ YELLOW = '\033[1;33m'
+ BLUE = '\033[0;34m'
+ CYAN = '\033[0;36m'
+ NC = '\033[0m' # No Color
+
+
+def log_info(msg: str) -> None:
+ print(f"{Colors.GREEN}[INFO]{Colors.NC} {msg}")
+
+
+def log_warn(msg: str) -> None:
+ print(f"{Colors.YELLOW}[WARN]{Colors.NC} {msg}")
+
+
+def log_error(msg: str) -> None:
+ print(f"{Colors.RED}[ERROR]{Colors.NC} {msg}")
+
+
+def extract_bundle_version(jar_path: Path) -> str | None:
+ """Extract Bundle-Version from JAR manifest."""
+ try:
+ with zipfile.ZipFile(jar_path, 'r') as zf:
+ manifest_data = zf.read('META-INF/MANIFEST.MF').decode('utf-8')
+ except (zipfile.BadZipFile, KeyError, IOError):
+ return None
+
+ # Parse manifest (handle line continuations)
+ lines = manifest_data.replace('\r\n ', '').replace('\r\n\t', '').split('\r\n')
+ if len(lines) == 1:
+ lines = manifest_data.replace('\n ', '').replace('\n\t', '').split('\n')
+
+ for line in lines:
+ if line.startswith('Bundle-Version:'):
+ return line.split(':', 1)[1].strip()
+ return None
+
+
+def is_snapshot_version(version: str) -> bool:
+ """Check if a version string indicates a snapshot."""
+ return 'SNAPSHOT' in version.upper()
+
+
+def find_built_jars(goss_dir: Path) -> list[Path]:
+ """Find all built JAR files in GOSS project."""
+ jars = []
+
+ # Look in generated directories for bundle JARs
+ for generated_dir in goss_dir.rglob('generated'):
+ for jar in generated_dir.glob('*.jar'):
+ if jar.is_file():
+ jars.append(jar)
+
+ return jars
+
+
+def get_bundle_name_from_jar(jar_path: Path) -> str | None:
+ """Extract Bundle-SymbolicName from JAR manifest."""
+ try:
+ with zipfile.ZipFile(jar_path, 'r') as zf:
+ manifest_data = zf.read('META-INF/MANIFEST.MF').decode('utf-8')
+ except (zipfile.BadZipFile, KeyError, IOError):
+ return None
+
+ # Parse manifest
+ lines = manifest_data.replace('\r\n ', '').replace('\r\n\t', '').split('\r\n')
+ if len(lines) == 1:
+ lines = manifest_data.replace('\n ', '').replace('\n\t', '').split('\n')
+
+ for line in lines:
+ if line.startswith('Bundle-SymbolicName:'):
+ bsn = line.split(':', 1)[1].strip()
+ # Remove directives
+ if ';' in bsn:
+ bsn = bsn.split(';')[0].strip()
+ return bsn
+ return None
+
+
+def main() -> int:
+ parser = argparse.ArgumentParser(
+ description='Push GOSS artifacts to GOSS-Repository (release or snapshot)',
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ epilog='''
+Examples:
+ %(prog)s --snapshot # Push snapshot versions to snapshot/
+ %(prog)s --release # Push release versions to release/
+ %(prog)s --snapshot --dry-run # Show what would be copied
+ %(prog)s --repo /path/to/GOSS-Repository --snapshot
+'''
+ )
+ parser.add_argument(
+ '--repo', '-r',
+ type=Path,
+ default=None,
+ help='Path to GOSS-Repository (default: ../GOSS-Repository)'
+ )
+ target_group = parser.add_mutually_exclusive_group(required=True)
+ target_group.add_argument(
+ '--snapshot', '-s',
+ action='store_true',
+ help='Push to snapshot/ directory'
+ )
+ target_group.add_argument(
+ '--release',
+ action='store_true',
+ help='Push to release/ directory'
+ )
+ parser.add_argument(
+ '--dry-run', '-n',
+ action='store_true',
+ help='Show what would be copied without actually copying'
+ )
+ parser.add_argument(
+ '--no-index',
+ action='store_true',
+ help='Skip generating repository index after copying'
+ )
+ parser.add_argument(
+ '--force', '-f',
+ action='store_true',
+ help='Overwrite existing JARs even if same size'
+ )
+
+ args = parser.parse_args()
+
+ script_dir = Path(__file__).parent.resolve()
+
+ # Determine repository path
+ if args.repo:
+ goss_repo_dir = args.repo.resolve()
+ else:
+ goss_repo_dir = script_dir.parent / 'GOSS-Repository'
+
+ # Determine target directory
+ if args.snapshot:
+ target_name = 'snapshot'
+ else:
+ target_name = 'release'
+
+ dest_repo_dir = goss_repo_dir / target_name
+
+ # Validate destination repository
+ if not goss_repo_dir.is_dir():
+ log_error(f"GOSS-Repository not found at: {goss_repo_dir}")
+ print()
+ print(f" The GOSS-Repository must be cloned locally as a sibling directory.")
+ print(f" Expected location: {goss_repo_dir}")
+ print()
+ print(f" To fix this, clone the repository:")
+ print(f" cd {script_dir.parent}")
+ print(f" git clone https://github.com/GridOPTICS/GOSS-Repository.git")
+ print()
+ print(f" Or specify a custom path with --repo:")
+ print(f" {sys.argv[0]} --repo /path/to/GOSS-Repository --{target_name}")
+ return 1
+
+ if not dest_repo_dir.is_dir():
+ log_error(f"Target directory not found: {dest_repo_dir}")
+ print()
+ print(f" The '{target_name}/' directory does not exist in GOSS-Repository.")
+ print(f" Please create it or check that you have the correct repository.")
+ return 1
+
+ log_info(f"GOSS Directory: {script_dir}")
+ log_info(f"Target: {dest_repo_dir}")
+
+ if args.dry_run:
+ log_info(f"{Colors.YELLOW}DRY RUN - no files will be copied{Colors.NC}")
+
+ # Find built JARs
+ built_jars = find_built_jars(script_dir)
+
+ if not built_jars:
+ log_warn("No built JARs found. Run './gradlew build' first.")
+ return 1
+
+ log_info(f"Found {len(built_jars)} built JAR(s)")
+
+ # Track statistics
+ copied_count = 0
+ skipped_count = 0
+ updated_count = 0
+ version_mismatch_count = 0
+
+ # Process each JAR
+ for jar_file in sorted(built_jars):
+ version = extract_bundle_version(jar_file)
+ bsn = get_bundle_name_from_jar(jar_file)
+
+ if not version or not bsn:
+ log_warn(f" Skipping (no OSGi metadata): {jar_file.name}")
+ continue
+
+ # Check if version matches target type
+ is_snapshot = is_snapshot_version(version)
+ if args.snapshot and not is_snapshot:
+ version_mismatch_count += 1
+ continue
+ if args.release and is_snapshot:
+ version_mismatch_count += 1
+ continue
+
+ # Determine destination path: //-.jar
+ dest_dir = dest_repo_dir / bsn
+ dest_filename = f"{bsn}-{version}.jar"
+ dest_path = dest_dir / dest_filename
+
+ # Check if already exists
+ if dest_path.exists():
+ source_size = jar_file.stat().st_size
+ dest_size = dest_path.stat().st_size
+
+ if source_size == dest_size and not args.force:
+ skipped_count += 1
+ continue
+ else:
+ if not args.dry_run:
+ shutil.copy2(str(jar_file), str(dest_path))
+ log_info(f" Updated: {bsn}/{dest_filename}")
+ updated_count += 1
+ else:
+ if not args.dry_run:
+ dest_dir.mkdir(parents=True, exist_ok=True)
+ shutil.copy2(str(jar_file), str(dest_path))
+ log_info(f" Copied: {bsn}/{dest_filename}")
+ copied_count += 1
+
+ # Summary
+ print()
+ print(f"{Colors.GREEN}========================================{Colors.NC}")
+ print(f"{Colors.GREEN}Push to GOSS-Repository Complete!{Colors.NC}")
+ print(f" Target: {Colors.CYAN}{target_name}/{Colors.NC}")
+ print(f" New JARs copied: {Colors.GREEN}{copied_count}{Colors.NC}")
+ print(f" JARs updated: {Colors.BLUE}{updated_count}{Colors.NC}")
+ print(f" JARs skipped: {Colors.YELLOW}{skipped_count}{Colors.NC} (same size, use --force to overwrite)")
+ if version_mismatch_count > 0:
+ print(f" Version mismatch: {Colors.YELLOW}{version_mismatch_count}{Colors.NC} (wrong type for target)")
+ print(f"{Colors.GREEN}========================================{Colors.NC}")
+ print()
+
+ # Generate repository index
+ if not args.no_index and not args.dry_run and (copied_count > 0 or updated_count > 0):
+ log_info(f"Generating repository index for {target_name}/...")
+
+ sh_script = goss_repo_dir / 'generate-repository-index.sh'
+
+ if sh_script.exists():
+ result = subprocess.run(
+ ['bash', str(sh_script), target_name],
+ cwd=goss_repo_dir
+ )
+ if result.returncode != 0:
+ log_warn("generate-repository-index.sh failed")
+ else:
+ log_warn("generate-repository-index.sh not found, skipping index generation")
+
+ if args.dry_run:
+ log_info(f"{Colors.YELLOW}DRY RUN complete - no files were modified{Colors.NC}")
+ else:
+ log_info(f"{Colors.GREEN}✓ All done!{Colors.NC}")
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/release.sh b/release.sh
new file mode 100755
index 00000000..50659f03
--- /dev/null
+++ b/release.sh
@@ -0,0 +1,223 @@
+#!/bin/bash
+#
+# GOSS Release Script
+# Usage: ./release.sh [release|snapshot] [version]
+#
+# Examples:
+# ./release.sh release # Remove -SNAPSHOT from all versions
+# ./release.sh snapshot # Add -SNAPSHOT to all versions
+# ./release.sh release 11.0.0 # Set specific release version
+# ./release.sh snapshot 11.0.1 # Set specific snapshot version
+
+set -e # Exit on error
+
+SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+cd "$SCRIPT_DIR"
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+# Function to print colored messages
+log_info() {
+ echo -e "${GREEN}[INFO]${NC} $1"
+}
+
+log_warn() {
+ echo -e "${YELLOW}[WARN]${NC} $1"
+}
+
+log_error() {
+ echo -e "${RED}[ERROR]${NC} $1"
+}
+
+# Function to find all .bnd files
+find_bnd_files() {
+ find . -name "*.bnd" -type f | grep -v ".gradle" | grep -v "build/"
+}
+
+# Function to find all packageinfo files
+find_packageinfo_files() {
+ find . -name "packageinfo" -type f | grep -v "build/"
+}
+
+# Function to get current version from a file
+get_current_version() {
+ local file=$1
+ grep "Bundle-Version:\|^version" "$file" | head -1 | sed 's/.*: *//' | sed 's/version *//'
+}
+
+# Function to update version in a file
+update_version() {
+ local file=$1
+ local new_version=$2
+ local current_version=$(get_current_version "$file")
+
+ if [[ "$file" == *"packageinfo"* ]]; then
+ sed -i "s/version .*/version $new_version/" "$file"
+ else
+ sed -i "s/Bundle-Version: .*/Bundle-Version: $new_version/" "$file"
+ fi
+
+ log_info " Updated: $file ($current_version -> $new_version)"
+}
+
+# Function to remove -SNAPSHOT suffix
+remove_snapshot() {
+ local version=$1
+ echo "$version" | sed 's/-SNAPSHOT//'
+}
+
+# Function to add -SNAPSHOT suffix
+add_snapshot() {
+ local version=$1
+ if [[ "$version" == *"-SNAPSHOT" ]]; then
+ echo "$version"
+ else
+ echo "$version-SNAPSHOT"
+ fi
+}
+
+# Function to bump version (e.g., 11.0.0 -> 11.0.1)
+bump_patch_version() {
+ local version=$1
+ # Remove -SNAPSHOT if present
+ version=$(remove_snapshot "$version")
+
+ # Split version into parts
+ local major=$(echo "$version" | cut -d. -f1)
+ local minor=$(echo "$version" | cut -d. -f2)
+ local patch=$(echo "$version" | cut -d. -f3)
+
+ # Increment patch version
+ patch=$((patch + 1))
+
+ echo "$major.$minor.$patch"
+}
+
+# Main logic
+MODE=${1:-help}
+TARGET_VERSION=$2
+
+case "$MODE" in
+ release)
+ log_info "Removing -SNAPSHOT from all versions..."
+
+ # Update .bnd files
+ for file in $(find_bnd_files); do
+ current_version=$(get_current_version "$file")
+ new_version=$(remove_snapshot "$current_version")
+
+ if [[ -n "$TARGET_VERSION" ]]; then
+ new_version="$TARGET_VERSION"
+ fi
+
+ if [[ "$current_version" != "$new_version" ]]; then
+ update_version "$file" "$new_version"
+ fi
+ done
+
+ # Update packageinfo files
+ for file in $(find_packageinfo_files); do
+ current_version=$(get_current_version "$file")
+ new_version=$(remove_snapshot "$current_version")
+
+ if [[ -n "$TARGET_VERSION" ]]; then
+ new_version="$TARGET_VERSION"
+ fi
+
+ if [[ "$current_version" != "$new_version" ]]; then
+ update_version "$file" "$new_version"
+ fi
+ done
+
+ log_info "Building release version..."
+ ./gradlew clean build -x test
+
+ log_info "${GREEN}✓ Release build complete!${NC}"
+ ;;
+
+ snapshot)
+ log_info "Adding -SNAPSHOT to all versions..."
+
+ # Update .bnd files
+ for file in $(find_bnd_files); do
+ current_version=$(get_current_version "$file")
+
+ if [[ -n "$TARGET_VERSION" ]]; then
+ new_version=$(add_snapshot "$TARGET_VERSION")
+ else
+ # If no target version, just add SNAPSHOT to current
+ new_version=$(add_snapshot "$current_version")
+ fi
+
+ if [[ "$current_version" != "$new_version" ]]; then
+ update_version "$file" "$new_version"
+ fi
+ done
+
+ # Update packageinfo files
+ for file in $(find_packageinfo_files); do
+ current_version=$(get_current_version "$file")
+
+ if [[ -n "$TARGET_VERSION" ]]; then
+ new_version=$(add_snapshot "$TARGET_VERSION")
+ else
+ new_version=$(add_snapshot "$current_version")
+ fi
+
+ if [[ "$current_version" != "$new_version" ]]; then
+ update_version "$file" "$new_version"
+ fi
+ done
+
+ log_info "${GREEN}✓ Version updated to SNAPSHOT${NC}"
+ ;;
+
+ bump)
+ log_info "Bumping version and adding -SNAPSHOT..."
+
+ # Get first version to determine base version
+ first_file=$(find_bnd_files | head -1)
+ base_version=$(get_current_version "$first_file")
+ base_version=$(remove_snapshot "$base_version")
+ new_version=$(bump_patch_version "$base_version")
+ new_version=$(add_snapshot "$new_version")
+
+ log_info "Bumping version: $base_version -> $new_version"
+
+ # Update all files
+ for file in $(find_bnd_files); do
+ update_version "$file" "$new_version"
+ done
+
+ for file in $(find_packageinfo_files); do
+ update_version "$file" "$new_version"
+ done
+
+ log_info "${GREEN}✓ Version bumped to $new_version${NC}"
+ ;;
+
+ help|*)
+ echo "GOSS Release Script"
+ echo ""
+ echo "Usage: ./release.sh [command] [version]"
+ echo ""
+ echo "Commands:"
+ echo " release Remove -SNAPSHOT from all versions and build"
+ echo " release [ver] Set all versions to specified release version and build"
+ echo " snapshot Add -SNAPSHOT to all versions"
+ echo " snapshot [ver] Set all versions to specified snapshot version"
+ echo " bump Increment patch version and add -SNAPSHOT"
+ echo " help Show this help message"
+ echo ""
+ echo "Examples:"
+ echo " ./release.sh release # 11.0.0-SNAPSHOT -> 11.0.0"
+ echo " ./release.sh release 11.1.0 # Set all to 11.1.0"
+ echo " ./release.sh snapshot # 11.0.0 -> 11.0.0-SNAPSHOT"
+ echo " ./release.sh snapshot 11.0.1 # Set all to 11.0.1-SNAPSHOT"
+ echo " ./release.sh bump # 11.0.0 -> 11.0.1-SNAPSHOT"
+ ;;
+esac
diff --git a/restore-jars.sh b/restore-jars.sh
new file mode 100755
index 00000000..422de426
--- /dev/null
+++ b/restore-jars.sh
@@ -0,0 +1,133 @@
+#!/bin/bash
+#
+# Restore JARs from master branch to current branch
+# Safely brings back historical releases without overwriting existing files
+#
+
+set -e
+
+SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+cd "$SCRIPT_DIR"
+
+# Colors
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+BLUE='\033[0;34m'
+NC='\033[0m'
+
+log_info() {
+ echo -e "${GREEN}[INFO]${NC} $1"
+}
+
+log_warn() {
+ echo -e "${YELLOW}[WARN]${NC} $1"
+}
+
+log_error() {
+ echo -e "${RED}[ERROR]${NC} $1"
+}
+
+# Check if we're in a git repo
+if ! git rev-parse --git-dir > /dev/null 2>&1; then
+ log_error "Not in a git repository"
+ exit 1
+fi
+
+# Get list of JARs in master
+log_info "Analyzing JARs in master branch..."
+MASTER_JARS=$(git ls-tree -r origin/master --name-only cnf/releaserepo/ | grep "\.jar$" | sort)
+MASTER_COUNT=$(echo "$MASTER_JARS" | wc -l)
+log_info "Found $MASTER_COUNT JARs in master"
+
+# Get list of JARs in current branch
+log_info "Analyzing JARs in current branch..."
+CURRENT_JARS=$(git ls-tree -r HEAD --name-only cnf/releaserepo/ | grep "\.jar$" | sort)
+CURRENT_COUNT=$(echo "$CURRENT_JARS" | wc -l)
+log_info "Found $CURRENT_COUNT JARs in current branch"
+
+# Find JARs to restore (in master but not in current)
+log_info "Calculating JARs to restore..."
+JARS_TO_RESTORE=$(comm -13 <(echo "$CURRENT_JARS") <(echo "$MASTER_JARS"))
+RESTORE_COUNT=$(echo "$JARS_TO_RESTORE" | grep -v '^$' | wc -l)
+
+log_info "${BLUE}JARs to restore: $RESTORE_COUNT${NC}"
+
+if [ "$RESTORE_COUNT" -eq 0 ]; then
+ log_info "No JARs to restore. Current branch has all JARs from master."
+ exit 0
+fi
+
+# Show summary
+echo ""
+echo -e "${BLUE}========================================${NC}"
+echo -e "${BLUE}Summary:${NC}"
+echo -e " Master branch: $MASTER_COUNT JARs"
+echo -e " Current branch: $CURRENT_COUNT JARs"
+echo -e " To restore: $RESTORE_COUNT JARs"
+echo -e "${BLUE}========================================${NC}"
+echo ""
+
+# Ask for confirmation
+read -p "Restore these JARs from master? (y/N): " -n 1 -r
+echo
+if [[ ! $REPLY =~ ^[Yy]$ ]]; then
+ log_warn "Restore cancelled"
+ exit 0
+fi
+
+# Create temporary directory
+TEMP_DIR=$(mktemp -d)
+log_info "Using temporary directory: $TEMP_DIR"
+
+# Track progress
+RESTORED=0
+FAILED=0
+
+log_info "Restoring JARs from master..."
+
+while IFS= read -r jar_path; do
+ if [ -z "$jar_path" ]; then
+ continue
+ fi
+
+ # Get the JAR from master branch
+ if git show "origin/master:$jar_path" > "$TEMP_DIR/temp.jar" 2>/dev/null; then
+ # Create directory if needed
+ mkdir -p "$(dirname "$jar_path")"
+
+ # Copy the JAR
+ mv "$TEMP_DIR/temp.jar" "$jar_path"
+
+ RESTORED=$((RESTORED + 1))
+
+ # Show progress every 50 JARs
+ if [ $((RESTORED % 50)) -eq 0 ]; then
+ log_info "Progress: $RESTORED/$RESTORE_COUNT JARs restored..."
+ fi
+ else
+ log_warn "Failed to restore: $jar_path"
+ FAILED=$((FAILED + 1))
+ fi
+done <<< "$JARS_TO_RESTORE"
+
+# Cleanup
+rm -rf "$TEMP_DIR"
+
+# Final summary
+echo ""
+echo -e "${GREEN}========================================${NC}"
+echo -e "${GREEN}Restore Complete!${NC}"
+echo -e " Restored: ${GREEN}$RESTORED${NC} JARs"
+if [ $FAILED -gt 0 ]; then
+ echo -e " Failed: ${RED}$FAILED${NC} JARs"
+fi
+echo -e "${GREEN}========================================${NC}"
+echo ""
+
+log_info "Updating repository index..."
+./gradlew :pnnl.goss.core:release
+
+log_info "${GREEN}✓ All done!${NC}"
+log_info "Run 'git status' to see the restored JARs"
+log_info "Run 'git add cnf/releaserepo/' to stage them"
diff --git a/scripts/check-api.py b/scripts/check-api.py
new file mode 100755
index 00000000..41fcc6af
--- /dev/null
+++ b/scripts/check-api.py
@@ -0,0 +1,449 @@
+#!/usr/bin/env python3
+"""
+GOSS API Change Detector
+
+Analyzes Java class files to detect API changes and suggest appropriate version bumps:
+- Major: Interface changes, removed public methods, breaking changes
+- Minor: New public methods on classes, new classes
+- Patch: Implementation-only changes
+
+Uses javap to extract public API signatures from JAR files.
+"""
+
+import argparse
+import hashlib
+import json
+import os
+import re
+import subprocess
+import sys
+import tempfile
+import zipfile
+from pathlib import Path
+from dataclasses import dataclass, field
+from typing import Optional
+
+
+# ANSI Colors
+class Colors:
+ RED = '\033[0;31m'
+ GREEN = '\033[0;32m'
+ YELLOW = '\033[1;33m'
+ BLUE = '\033[0;34m'
+ CYAN = '\033[0;36m'
+ MAGENTA = '\033[0;35m'
+ NC = '\033[0m' # No Color
+
+
+def log_info(msg: str) -> None:
+ print(f"{Colors.GREEN}[INFO]{Colors.NC} {msg}")
+
+
+def log_warn(msg: str) -> None:
+ print(f"{Colors.YELLOW}[WARN]{Colors.NC} {msg}")
+
+
+def log_error(msg: str) -> None:
+ print(f"{Colors.RED}[ERROR]{Colors.NC} {msg}")
+
+
+@dataclass
+class ClassInfo:
+ """Information about a Java class's public API."""
+ name: str
+ is_interface: bool = False
+ is_abstract: bool = False
+ is_enum: bool = False
+ superclass: Optional[str] = None
+ interfaces: list[str] = field(default_factory=list)
+ public_methods: list[str] = field(default_factory=list)
+ public_fields: list[str] = field(default_factory=list)
+
+ def signature_hash(self) -> str:
+ """Generate a hash of the public API signature."""
+ sig = f"{self.name}|{self.is_interface}|{self.superclass}|"
+ sig += "|".join(sorted(self.interfaces))
+ sig += "|".join(sorted(self.public_methods))
+ sig += "|".join(sorted(self.public_fields))
+ return hashlib.md5(sig.encode()).hexdigest()[:12]
+
+
+def extract_class_info(jar_path: Path, class_name: str) -> Optional[ClassInfo]:
+ """Extract public API information from a class using javap."""
+ try:
+ result = subprocess.run(
+ ['javap', '-public', '-classpath', str(jar_path), class_name],
+ capture_output=True,
+ text=True,
+ timeout=10
+ )
+ if result.returncode != 0:
+ return None
+
+ output = result.stdout
+ info = ClassInfo(name=class_name)
+
+ # Parse class declaration
+ class_match = re.search(
+ r'(public\s+)?(abstract\s+)?(interface|class|enum)\s+\S+',
+ output
+ )
+ if class_match:
+ info.is_interface = 'interface' in class_match.group(0)
+ info.is_abstract = 'abstract' in (class_match.group(0) or '')
+ info.is_enum = 'enum' in class_match.group(0)
+
+ # Parse extends
+ extends_match = re.search(r'extends\s+(\S+)', output)
+ if extends_match:
+ info.superclass = extends_match.group(1)
+
+ # Parse implements
+ implements_match = re.search(r'implements\s+([^{]+)', output)
+ if implements_match:
+ info.interfaces = [i.strip() for i in implements_match.group(1).split(',')]
+
+ # Parse public methods (simplified)
+ for line in output.split('\n'):
+ line = line.strip()
+ if line.startswith('public') and '(' in line and ')' in line:
+ # Extract method signature
+ method_sig = re.sub(r'\s+', ' ', line.rstrip(';'))
+ info.public_methods.append(method_sig)
+ elif line.startswith('public') and '(' not in line and ';' in line:
+ # Public field
+ info.public_fields.append(line.rstrip(';'))
+
+ return info
+ except Exception as e:
+ return None
+
+
+def list_classes_in_jar(jar_path: Path) -> list[str]:
+ """List all class files in a JAR."""
+ classes = []
+ try:
+ with zipfile.ZipFile(jar_path, 'r') as zf:
+ for name in zf.namelist():
+ if name.endswith('.class') and not name.startswith('META-INF/'):
+ # Convert path to class name
+ class_name = name[:-6].replace('/', '.')
+ # Skip inner classes for now
+ if '$' not in class_name:
+ classes.append(class_name)
+ except Exception:
+ pass
+ return sorted(classes)
+
+
+def analyze_jar(jar_path: Path) -> dict[str, ClassInfo]:
+ """Analyze all public APIs in a JAR file."""
+ apis = {}
+ classes = list_classes_in_jar(jar_path)
+
+ for class_name in classes:
+ info = extract_class_info(jar_path, class_name)
+ if info:
+ apis[class_name] = info
+
+ return apis
+
+
+@dataclass
+class ApiChange:
+ """Represents a single API change."""
+ change_type: str # 'major', 'minor', 'patch'
+ category: str # 'interface', 'class', 'method', 'field'
+ description: str
+ class_name: str
+
+
+def compare_apis(old_apis: dict[str, ClassInfo], new_apis: dict[str, ClassInfo]) -> list[ApiChange]:
+ """Compare two API snapshots and return list of changes."""
+ changes = []
+
+ old_classes = set(old_apis.keys())
+ new_classes = set(new_apis.keys())
+
+ # Removed classes = MAJOR (breaking change)
+ for removed in old_classes - new_classes:
+ old_info = old_apis[removed]
+ change_type = 'major' if old_info.is_interface else 'major'
+ changes.append(ApiChange(
+ change_type=change_type,
+ category='interface' if old_info.is_interface else 'class',
+ description=f"Removed: {removed}",
+ class_name=removed
+ ))
+
+ # Added classes = MINOR (backward compatible addition)
+ for added in new_classes - old_classes:
+ new_info = new_apis[added]
+ changes.append(ApiChange(
+ change_type='minor',
+ category='interface' if new_info.is_interface else 'class',
+ description=f"Added: {added}",
+ class_name=added
+ ))
+
+ # Changed classes
+ for class_name in old_classes & new_classes:
+ old_info = old_apis[class_name]
+ new_info = new_apis[class_name]
+
+ # Interface changes are always MAJOR
+ if old_info.is_interface or new_info.is_interface:
+ old_methods = set(old_info.public_methods)
+ new_methods = set(new_info.public_methods)
+
+ # Removed methods from interface = MAJOR
+ for removed in old_methods - new_methods:
+ changes.append(ApiChange(
+ change_type='major',
+ category='interface',
+ description=f"Interface method removed: {removed}",
+ class_name=class_name
+ ))
+
+ # Added methods to interface = MAJOR (breaks implementors)
+ for added in new_methods - old_methods:
+ changes.append(ApiChange(
+ change_type='major',
+ category='interface',
+ description=f"Interface method added: {added}",
+ class_name=class_name
+ ))
+ else:
+ # Class changes
+ old_methods = set(old_info.public_methods)
+ new_methods = set(new_info.public_methods)
+
+ # Removed public methods = MAJOR
+ for removed in old_methods - new_methods:
+ changes.append(ApiChange(
+ change_type='major',
+ category='method',
+ description=f"Public method removed: {removed}",
+ class_name=class_name
+ ))
+
+ # Added public methods = MINOR
+ for added in new_methods - old_methods:
+ changes.append(ApiChange(
+ change_type='minor',
+ category='method',
+ description=f"Public method added: {added}",
+ class_name=class_name
+ ))
+
+ # Check superclass changes = MAJOR
+ if old_info.superclass != new_info.superclass:
+ changes.append(ApiChange(
+ change_type='major',
+ category='class',
+ description=f"Superclass changed: {old_info.superclass} -> {new_info.superclass}",
+ class_name=class_name
+ ))
+
+ # Check interface changes = MAJOR (for classes)
+ old_interfaces = set(old_info.interfaces)
+ new_interfaces = set(new_info.interfaces)
+
+ for removed in old_interfaces - new_interfaces:
+ changes.append(ApiChange(
+ change_type='major',
+ category='class',
+ description=f"Interface removed: {removed}",
+ class_name=class_name
+ ))
+
+ return changes
+
+
+def find_baseline_jar(bundle_name: str, release_repo: Path) -> Optional[Path]:
+ """Find the baseline JAR for a bundle in the release repository."""
+ bundle_dir = release_repo / bundle_name
+ if not bundle_dir.is_dir():
+ return None
+
+ # Find the latest JAR
+ jars = list(bundle_dir.glob('*.jar'))
+ if not jars:
+ return None
+
+ # Sort by version (simple string sort works for semver)
+ jars.sort(key=lambda p: p.name, reverse=True)
+ return jars[0]
+
+
+def find_current_jar(bundle_name: str, goss_root: Path) -> Optional[Path]:
+ """Find the current built JAR for a bundle."""
+ for generated in goss_root.rglob('generated'):
+ for jar in generated.glob(f'{bundle_name}*.jar'):
+ if jar.is_file():
+ return jar
+ return None
+
+
+def get_bundle_name_from_jar(jar_path: Path) -> Optional[str]:
+ """Extract Bundle-SymbolicName from JAR manifest."""
+ try:
+ with zipfile.ZipFile(jar_path, 'r') as zf:
+ manifest = zf.read('META-INF/MANIFEST.MF').decode('utf-8')
+ for line in manifest.replace('\r\n ', '').replace('\n ', '').split('\n'):
+ if line.startswith('Bundle-SymbolicName:'):
+ bsn = line.split(':', 1)[1].strip()
+ if ';' in bsn:
+ bsn = bsn.split(';')[0].strip()
+ return bsn
+ except Exception:
+ pass
+ return None
+
+
+def main() -> int:
+ parser = argparse.ArgumentParser(
+ description='Analyze API changes and suggest version bump type',
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ epilog='''
+Version Bump Rules:
+ MAJOR (X.0.0): Interface changes, removed public methods, breaking changes
+ MINOR (x.Y.0): New public methods on classes, new classes (backward compatible)
+ PATCH (x.y.Z): Implementation-only changes, no public API changes
+
+Examples:
+ %(prog)s # Analyze all bundles
+ %(prog)s --bundle pnnl.goss.core.core-api # Analyze specific bundle
+ %(prog)s --verbose # Show detailed change information
+'''
+ )
+
+ parser.add_argument('--bundle', '-b', help='Specific bundle to analyze')
+ parser.add_argument('--verbose', '-v', action='store_true', help='Show detailed changes')
+ parser.add_argument('--baseline', help='Path to baseline repository (default: cnf/releaserepo)')
+
+ args = parser.parse_args()
+
+ script_dir = Path(__file__).parent.resolve()
+ goss_root = script_dir.parent
+
+ # Determine baseline repository
+ if args.baseline:
+ baseline_repo = Path(args.baseline)
+ else:
+ baseline_repo = goss_root / 'cnf' / 'releaserepo'
+
+ if not baseline_repo.is_dir():
+ log_warn(f"Baseline repository not found: {baseline_repo}")
+ log_warn("No baseline to compare against. All changes will be considered MINOR.")
+ log_warn("Run './gradlew release' to populate the baseline repository.")
+ print()
+
+ # Find all current JARs
+ current_jars = []
+ for generated in goss_root.rglob('generated'):
+ for jar in generated.glob('pnnl.goss.*.jar'):
+ if jar.is_file() and 'runner' not in jar.name:
+ current_jars.append(jar)
+
+ if not current_jars:
+ log_error("No built JARs found. Run './gradlew build' first.")
+ return 1
+
+ # Filter to specific bundle if requested
+ if args.bundle:
+ current_jars = [j for j in current_jars if args.bundle in j.name]
+ if not current_jars:
+ log_error(f"Bundle not found: {args.bundle}")
+ return 1
+
+ print(f"\n{Colors.CYAN}API Change Analysis{Colors.NC}")
+ print("=" * 60)
+
+ overall_bump = 'patch'
+ all_changes: list[ApiChange] = []
+
+ for current_jar in sorted(current_jars):
+ bundle_name = get_bundle_name_from_jar(current_jar)
+ if not bundle_name:
+ continue
+
+ baseline_jar = find_baseline_jar(bundle_name, baseline_repo)
+
+ print(f"\n{Colors.BLUE}{bundle_name}{Colors.NC}")
+
+ if not baseline_jar:
+ print(f" {Colors.YELLOW}No baseline found{Colors.NC} - treating as new bundle (MINOR)")
+ if overall_bump == 'patch':
+ overall_bump = 'minor'
+ continue
+
+ # Analyze both JARs
+ old_apis = analyze_jar(baseline_jar)
+ new_apis = analyze_jar(current_jar)
+
+ if not old_apis and not new_apis:
+ print(f" {Colors.YELLOW}Could not analyze APIs{Colors.NC}")
+ continue
+
+ # Compare
+ changes = compare_apis(old_apis, new_apis)
+ all_changes.extend(changes)
+
+ if not changes:
+ # Check if implementation changed (hash comparison)
+ old_hashes = {k: v.signature_hash() for k, v in old_apis.items()}
+ new_hashes = {k: v.signature_hash() for k, v in new_apis.items()}
+
+ if old_hashes == new_hashes:
+ print(f" {Colors.GREEN}No API changes{Colors.NC}")
+ else:
+ print(f" {Colors.GREEN}Implementation changes only{Colors.NC} (PATCH)")
+ else:
+ # Categorize changes
+ major_changes = [c for c in changes if c.change_type == 'major']
+ minor_changes = [c for c in changes if c.change_type == 'minor']
+
+ if major_changes:
+ print(f" {Colors.RED}MAJOR changes detected:{Colors.NC}")
+ overall_bump = 'major'
+ if args.verbose:
+ for c in major_changes[:5]:
+ print(f" - {c.description}")
+ if len(major_changes) > 5:
+ print(f" ... and {len(major_changes) - 5} more")
+ else:
+ print(f" {len(major_changes)} breaking change(s)")
+
+ if minor_changes:
+ print(f" {Colors.YELLOW}MINOR changes detected:{Colors.NC}")
+ if overall_bump == 'patch':
+ overall_bump = 'minor'
+ if args.verbose:
+ for c in minor_changes[:5]:
+ print(f" - {c.description}")
+ if len(minor_changes) > 5:
+ print(f" ... and {len(minor_changes) - 5} more")
+ else:
+ print(f" {len(minor_changes)} addition(s)")
+
+ # Summary
+ print("\n" + "=" * 60)
+ print(f"{Colors.CYAN}Recommended Version Bump:{Colors.NC}")
+
+ if overall_bump == 'major':
+ print(f" {Colors.RED}MAJOR{Colors.NC} - Breaking API changes detected")
+ print(f" Run: {Colors.CYAN}make bump-major{Colors.NC}")
+ elif overall_bump == 'minor':
+ print(f" {Colors.YELLOW}MINOR{Colors.NC} - New API additions (backward compatible)")
+ print(f" Run: {Colors.CYAN}make bump-minor{Colors.NC}")
+ else:
+ print(f" {Colors.GREEN}PATCH{Colors.NC} - Implementation changes only")
+ print(f" Run: {Colors.CYAN}make bump-patch{Colors.NC} or {Colors.CYAN}make next-snapshot{Colors.NC}")
+
+ print()
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/scripts/version.py b/scripts/version.py
new file mode 100755
index 00000000..5076006f
--- /dev/null
+++ b/scripts/version.py
@@ -0,0 +1,318 @@
+#!/usr/bin/env python3
+"""
+GOSS Version Management Script
+
+Commands:
+ show - Display versions of all bundles
+ release - Set release version (removes -SNAPSHOT)
+ snapshot - Set snapshot version (adds -SNAPSHOT)
+ bump-patch - Bump patch version (x.y.Z) and set as snapshot
+ bump-minor - Bump minor version (x.Y.0) and set as snapshot
+ bump-major - Bump major version (X.0.0) and set as snapshot
+ next-snapshot - Bump patch version after a release
+"""
+
+import argparse
+import re
+import sys
+from pathlib import Path
+
+
+# ANSI Colors
+class Colors:
+ RED = '\033[0;31m'
+ GREEN = '\033[0;32m'
+ YELLOW = '\033[1;33m'
+ BLUE = '\033[0;34m'
+ CYAN = '\033[0;36m'
+ NC = '\033[0m' # No Color
+
+
+def log_info(msg: str) -> None:
+ print(f"{Colors.GREEN}[INFO]{Colors.NC} {msg}")
+
+
+def log_warn(msg: str) -> None:
+ print(f"{Colors.YELLOW}[WARN]{Colors.NC} {msg}")
+
+
+def log_error(msg: str) -> None:
+ print(f"{Colors.RED}[ERROR]{Colors.NC} {msg}")
+
+
+def find_bnd_files(root: Path) -> list[Path]:
+ """Find all .bnd files that contain Bundle-Version."""
+ bnd_files = []
+ for bnd_file in root.rglob('*.bnd'):
+ # Skip cnf/ext directory (these are config files, not bundles)
+ if 'cnf/ext' in str(bnd_file):
+ continue
+ # Skip cnf/build.bnd and cnf/bnd.bnd (workspace config)
+ if bnd_file.parent.name == 'cnf' and bnd_file.name in ('build.bnd', 'bnd.bnd'):
+ continue
+ # Check if file contains Bundle-Version
+ content = bnd_file.read_text()
+ if 'Bundle-Version:' in content:
+ bnd_files.append(bnd_file)
+ return sorted(bnd_files)
+
+
+def extract_bundle_info(bnd_file: Path) -> tuple[str, str] | None:
+ """Extract bundle name and version from a .bnd file."""
+ content = bnd_file.read_text()
+
+ # Extract Bundle-Version
+ version_match = re.search(r'Bundle-Version:\s*(.+)', content)
+ if not version_match:
+ return None
+
+ version = version_match.group(1).strip()
+
+ # Derive bundle name from file path
+ # e.g., pnnl.goss.core/core-api.bnd -> pnnl.goss.core.core-api
+ parent_dir = bnd_file.parent.name
+ bundle_name = bnd_file.stem
+
+ if bundle_name == 'bnd':
+ # Main bundle file (e.g., pnnl.goss.core/bnd.bnd)
+ full_name = parent_dir
+ else:
+ # Sub-bundle file (e.g., pnnl.goss.core/core-api.bnd)
+ full_name = f"{parent_dir}.{bundle_name}"
+
+ return (full_name, version)
+
+
+def show_versions(root: Path) -> None:
+ """Display versions of all bundles."""
+ bnd_files = find_bnd_files(root)
+
+ if not bnd_files:
+ log_warn("No bundle .bnd files found")
+ return
+
+ print(f"\n{Colors.CYAN}GOSS Bundle Versions{Colors.NC}")
+ print("=" * 60)
+
+ # Group by version
+ versions: dict[str, list[str]] = {}
+
+ for bnd_file in bnd_files:
+ info = extract_bundle_info(bnd_file)
+ if info:
+ name, version = info
+ if version not in versions:
+ versions[version] = []
+ versions[version].append(name)
+
+ # Display grouped by version
+ for version in sorted(versions.keys()):
+ is_snapshot = '-SNAPSHOT' in version
+ version_color = Colors.YELLOW if is_snapshot else Colors.GREEN
+ print(f"\n{version_color}{version}{Colors.NC}:")
+ for name in sorted(versions[version]):
+ print(f" - {name}")
+
+ print("\n" + "=" * 60)
+ print(f"Total bundles: {sum(len(v) for v in versions.values())}")
+
+ # Summary
+ snapshot_count = sum(len(v) for ver, v in versions.items() if '-SNAPSHOT' in ver)
+ release_count = sum(len(v) for ver, v in versions.items() if '-SNAPSHOT' not in ver)
+
+ if snapshot_count > 0:
+ print(f" {Colors.YELLOW}Snapshot:{Colors.NC} {snapshot_count}")
+ if release_count > 0:
+ print(f" {Colors.GREEN}Release:{Colors.NC} {release_count}")
+ print()
+
+
+def update_version(bnd_file: Path, new_version: str) -> bool:
+ """Update Bundle-Version in a .bnd file."""
+ content = bnd_file.read_text()
+
+ # Replace Bundle-Version line
+ new_content, count = re.subn(
+ r'(Bundle-Version:\s*).+',
+ f'\\g<1>{new_version}',
+ content
+ )
+
+ if count > 0:
+ bnd_file.write_text(new_content)
+ return True
+ return False
+
+
+def get_current_version(root: Path) -> str | None:
+ """Get the current version from .bnd files (returns base version without -SNAPSHOT)."""
+ bnd_files = find_bnd_files(root)
+
+ versions: set[str] = set()
+ for bnd_file in bnd_files:
+ info = extract_bundle_info(bnd_file)
+ if info:
+ _, version = info
+ # Strip -SNAPSHOT suffix for comparison
+ base_version = version.replace('-SNAPSHOT', '')
+ versions.add(base_version)
+
+ if len(versions) == 0:
+ return None
+ if len(versions) > 1:
+ log_warn(f"Multiple versions found: {sorted(versions)}")
+ # Return the highest version
+ return sorted(versions, key=lambda v: [int(x) for x in v.split('.')])[-1]
+
+ return versions.pop()
+
+
+def bump_version(version: str, bump_type: str) -> str:
+ """Bump a version string by the specified type (major, minor, patch)."""
+ parts = [int(x) for x in version.split('.')]
+
+ if bump_type == 'major':
+ parts[0] += 1
+ parts[1] = 0
+ parts[2] = 0
+ elif bump_type == 'minor':
+ parts[1] += 1
+ parts[2] = 0
+ elif bump_type == 'patch':
+ parts[2] += 1
+
+ return '.'.join(str(p) for p in parts)
+
+
+def set_version(root: Path, version: str, snapshot: bool = False) -> None:
+ """Set version for all bundles."""
+ # Validate version format
+ if not re.match(r'^\d+\.\d+\.\d+$', version):
+ log_error(f"Invalid version format: {version}")
+ log_error("Expected format: x.y.z (e.g., 11.0.0)")
+ sys.exit(1)
+
+ # Add or remove -SNAPSHOT suffix
+ if snapshot:
+ full_version = f"{version}-SNAPSHOT"
+ else:
+ full_version = version
+
+ bnd_files = find_bnd_files(root)
+
+ if not bnd_files:
+ log_warn("No bundle .bnd files found")
+ return
+
+ action = "snapshot" if snapshot else "release"
+ log_info(f"Setting {action} version: {full_version}")
+ print()
+
+ updated_count = 0
+ for bnd_file in bnd_files:
+ info = extract_bundle_info(bnd_file)
+ if info:
+ name, old_version = info
+ if update_version(bnd_file, full_version):
+ rel_path = bnd_file.relative_to(root)
+ print(f" {Colors.GREEN}✓{Colors.NC} {name}: {old_version} -> {full_version}")
+ updated_count += 1
+
+ print()
+ log_info(f"Updated {updated_count} bundle(s) to version {full_version}")
+
+ if not snapshot:
+ print()
+ log_info("Next steps for release:")
+ print(f" 1. Build: ./gradlew build")
+ print(f" 2. Test: ./gradlew check")
+ print(f" 3. Commit: git commit -am 'Release version {version}'")
+ print(f" 4. Tag: git tag -a v{version} -m 'Version {version}'")
+ print(f" 5. Push: git push && git push --tags")
+ print()
+
+
+def do_bump(root: Path, bump_type: str) -> int:
+ """Bump version and set as snapshot."""
+ current = get_current_version(root)
+ if not current:
+ log_error("Could not determine current version")
+ return 1
+
+ new_version = bump_version(current, bump_type)
+ log_info(f"Bumping {bump_type} version: {current} -> {new_version}-SNAPSHOT")
+ set_version(root, new_version, snapshot=True)
+ return 0
+
+
+def main() -> int:
+ parser = argparse.ArgumentParser(
+ description='GOSS Version Management',
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ epilog='''
+Examples:
+ %(prog)s show # Show all bundle versions
+ %(prog)s release 11.0.0 # Set release version 11.0.0
+ %(prog)s snapshot 11.1.0 # Set snapshot version 11.1.0-SNAPSHOT
+ %(prog)s bump-patch # 11.0.0 -> 11.0.1-SNAPSHOT
+ %(prog)s bump-minor # 11.0.0 -> 11.1.0-SNAPSHOT
+ %(prog)s bump-major # 11.0.0 -> 12.0.0-SNAPSHOT
+ %(prog)s next-snapshot # After release: bump patch to next snapshot
+
+Typical release workflow:
+ 1. %(prog)s show # Verify current version (e.g., 11.0.0-SNAPSHOT)
+ 2. %(prog)s release 11.0.0 # Remove -SNAPSHOT for release
+ 3. make build && make test # Build and test
+ 4. make push-release # Push to GOSS-Repository
+ 5. git tag v11.0.0 && git push # Tag and push
+ 6. %(prog)s next-snapshot # Bump to 11.0.1-SNAPSHOT for next development
+'''
+ )
+
+ subparsers = parser.add_subparsers(dest='command', help='Command to run')
+
+ # show command
+ subparsers.add_parser('show', help='Show versions of all bundles')
+
+ # release command
+ release_parser = subparsers.add_parser('release', help='Set release version (removes -SNAPSHOT)')
+ release_parser.add_argument('version', help='Version number (e.g., 11.0.0)')
+
+ # snapshot command
+ snapshot_parser = subparsers.add_parser('snapshot', help='Set snapshot version (adds -SNAPSHOT)')
+ snapshot_parser.add_argument('version', help='Version number (e.g., 11.1.0)')
+
+ # bump commands
+ subparsers.add_parser('bump-patch', help='Bump patch version (x.y.Z) and set as snapshot')
+ subparsers.add_parser('bump-minor', help='Bump minor version (x.Y.0) and set as snapshot')
+ subparsers.add_parser('bump-major', help='Bump major version (X.0.0) and set as snapshot')
+ subparsers.add_parser('next-snapshot', help='Bump patch version after a release (alias for bump-patch)')
+
+ args = parser.parse_args()
+
+ # Find root directory (where this script's parent's parent is)
+ script_dir = Path(__file__).parent.resolve()
+ root = script_dir.parent
+
+ if not args.command:
+ parser.print_help()
+ return 1
+
+ if args.command == 'show':
+ show_versions(root)
+ elif args.command == 'release':
+ set_version(root, args.version, snapshot=False)
+ elif args.command == 'snapshot':
+ set_version(root, args.version, snapshot=True)
+ elif args.command in ('bump-patch', 'next-snapshot'):
+ return do_bump(root, 'patch')
+ elif args.command == 'bump-minor':
+ return do_bump(root, 'minor')
+ elif args.command == 'bump-major':
+ return do_bump(root, 'major')
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/settings.gradle b/settings.gradle
index 5d64c993..ab2cfb80 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,127 +1,13 @@
/*
* Master Gradle initialization script
- *
- * Depends on bnd_* values from gradle.properties.
+ * Simplified for JDK 22 compatibility
*/
-import aQute.bnd.build.Workspace
+// Include the standard BND projects discovered by the workspace
+rootProject.name = 'goss'
-/* Add bnd as a script dependency */
-buildscript {
- dependencies {
- def bndURI = rootDir.toURI().resolve(bnd_jar)
- if (bndURI.scheme != 'file') {
- /* If not a local file, copy to a local file in cnf/cache */
- def cnfCache = mkdir("${rootDir}/${bnd_cnf}/cache")
- def bndJarFile = new File(cnfCache, 'biz.aQute.bnd.gradle.jar')
- if (!bndJarFile.exists()) {
- println "Downloading ${bndURI} to ${bndJarFile} ..."
- bndURI.toURL().withInputStream { is ->
- bndJarFile.withOutputStream { os ->
- def bos = new BufferedOutputStream( os )
- bos << is
- }
- }
- }
- bndURI = bndJarFile.toURI()
- }
- classpath files(bndURI)
-
- /* After the rootProject is created, pass URI to projects */
- gradle.rootProject { rootProject ->
- rootProject.ext.bndURI = bndURI
- }
- }
-}
-
-/* Initialize the bnd workspace */
-def workspace = Workspace.getWorkspace(rootDir, bnd_cnf)
-if (workspace == null) {
- throw new GradleException("Unable to load workspace ${rootDir}/${bnd_cnf}")
-}
-
-/* Add cnf project to the graph */
-include bnd_cnf
-
-/* Start with the declared build project name */
-def defaultProjectName = bnd_build
-
-/* If in a subproject, use the subproject name */
-for (def currentDir = startParameter.currentDir; currentDir != rootDir; currentDir = currentDir.parentFile) {
- defaultProjectName = currentDir.name
-}
-
-/* Build a set of project names we need to include from the specified tasks */
-def projectNames = startParameter.taskNames.collect { taskName ->
- def elements = taskName.split(':')
- switch (elements.length) {
- case 1:
- return defaultProjectName
- case 2:
- return elements[0].empty ? bnd_build : elements[0]
- default:
- return elements[0].empty ? elements[1] : elements[0]
- }
-}.toSet()
-
-/* Include the default project name if in a subproject or no tasks specified */
-if ((startParameter.currentDir != rootDir) || projectNames.empty) {
- projectNames += defaultProjectName
-}
-
-/* If bnd_build used but declared empty, add all non-private folders of rootDir */
-if (projectNames.remove('')) {
- rootDir.eachDir {
- def projectName = it.name
- if (!projectName.startsWith('.')) {
- projectNames += projectName
- }
- }
-}
-
-/* Add each project and its dependencies to the graph */
-projectNames.each { projectName ->
- include projectName
- def project = getBndProject(workspace, projectName)
- project?.dependson.each {
- include it.name
- }
-}
-
-/* Get the bnd project for the specified project name */
-def getBndProject(Workspace workspace, String projectName) {
- def project = workspace.getProject(projectName)
- if (project == null) {
- return null
- }
- project.prepare()
- if (project.isValid()) {
- return project
- }
-
- project.getInfo(workspace, "${rootDir} :")
- def errorCount = 0
- project.warnings.each {
- println "Warning: ${it}"
- }
- project.errors.each {
- println "Error : ${it}"
- errorCount++
- }
- if (!project.isOk()) {
- def str = 'even though no errors were reported'
- if (errorCount == 1) {
- str = 'one error was reported'
- } else if (errorCount > 1) {
- str = "${errorCount} errors were reported"
- }
- throw new GradleException("Project ${rootDir}/${projectName} is invalid, ${str}")
- }
- throw new GradleException("Project ${rootDir}/${projectName} is not a valid bnd project")
-}
-
-/* After the rootProject is created, set up some properties. */
-gradle.rootProject { rootProject ->
- rootProject.ext.bndWorkspace = workspace
- rootProject.ext.cnf = rootProject.project(bnd_cnf)
-}
+// Add the main modules
+include 'pnnl.goss.core'
+include 'pnnl.goss.core.runner'
+include 'pnnl.goss.core.itests' // Note: Felix DM migration complete; using OSGi DS. If any export support is still pending, clarify here.
+include 'pnnl.goss.core.testutil'
\ No newline at end of file