summaryrefslogtreecommitdiffstats
path: root/auth/auth-locate
diff options
context:
space:
mode:
Diffstat (limited to 'auth/auth-locate')
-rw-r--r--auth/auth-locate/.gitignore6
-rw-r--r--auth/auth-locate/pom.xml113
-rw-r--r--auth/auth-locate/src/main/.gitignore0
-rw-r--r--auth/auth-locate/src/main/config/.gitignore2
-rw-r--r--auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/AAF_Locate.java243
-rw-r--r--auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/BasicAuthCode.java77
-rw-r--r--auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/LocateCode.java44
-rw-r--r--auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_AAFAccess.java259
-rw-r--r--auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Api.java97
-rw-r--r--auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Find.java132
-rw-r--r--auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Proxy.java163
-rw-r--r--auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacade.java106
-rw-r--r--auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacadeFactory.java48
-rw-r--r--auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacadeImpl.java393
-rw-r--r--auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacade_1_0.java40
-rw-r--r--auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/mapper/Mapper.java41
-rw-r--r--auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/mapper/Mapper_1_0.java150
-rw-r--r--auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateService.java33
-rw-r--r--auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateServiceImpl.java122
-rw-r--r--auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/validation/LocateValidator.java141
-rw-r--r--auth/auth-locate/src/main/xsd/locate_1_0.xsd122
21 files changed, 2332 insertions, 0 deletions
diff --git a/auth/auth-locate/.gitignore b/auth/auth-locate/.gitignore
new file mode 100644
index 00000000..3fea7c64
--- /dev/null
+++ b/auth/auth-locate/.gitignore
@@ -0,0 +1,6 @@
+/target/
+/.classpath
+/logs/
+/.settings/
+/tokens/
+/.project
diff --git a/auth/auth-locate/pom.xml b/auth/auth-locate/pom.xml
new file mode 100644
index 00000000..4fb54db3
--- /dev/null
+++ b/auth/auth-locate/pom.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.onap.aaf.auth</groupId>
+ <artifactId>parent</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>aaf-auth-locate</artifactId>
+ <name>AAF Auth Locate</name>
+ <description>Location Service for AAF Auth Components</description>
+
+ <properties>
+ <maven.test.failure.ignore>true</maven.test.failure.ignore>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onap.aaf.auth</groupId>
+ <artifactId>aaf-auth-core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onap.aaf.auth</groupId>
+ <artifactId>aaf-auth-cass</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.onap.aaf.cadi</groupId>
+ <artifactId>aaf-cadi-aaf</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.jvnet.jaxb2.maven2</groupId>
+ <artifactId>maven-jaxb2-plugin</artifactId>
+ <version>0.8.2</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <schemaDirectory>src/main/xsd</schemaDirectory>
+ </configuration>
+ </plugin>
+
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>appassembler-maven-plugin</artifactId>
+ <configuration>
+ <programs>
+ <program>
+ <mainClass>org.onap.aaf.auth.locate.AAF_Locate</mainClass>
+ <id>locate</id>
+ <commandLineArguments>
+ <commandLineArgument>cadi_prop_files=${project.conf_dir}/org.osaaf.locate.props</commandLineArgument>
+ </commandLineArguments>
+ </program>
+ </programs>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <distributionManagement>
+ <repository>
+ <id>nexus</id>
+ <name>attarch-releases</name>
+ <url>http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-releases</url>
+ </repository>
+ <snapshotRepository>
+ <id>nexus</id>
+ <name>attarch-snapshots</name>
+ <url>http://mavencentral.it.att.com:8084/nexus/content/repositories/attarch-snapshots</url>
+ </snapshotRepository>
+ </distributionManagement>
+</project>
diff --git a/auth/auth-locate/src/main/.gitignore b/auth/auth-locate/src/main/.gitignore
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/auth/auth-locate/src/main/.gitignore
diff --git a/auth/auth-locate/src/main/config/.gitignore b/auth/auth-locate/src/main/config/.gitignore
new file mode 100644
index 00000000..429128d5
--- /dev/null
+++ b/auth/auth-locate/src/main/config/.gitignore
@@ -0,0 +1,2 @@
+/authGW.props
+/log4j.properties
diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/AAF_Locate.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/AAF_Locate.java
new file mode 100644
index 00000000..92fc88c7
--- /dev/null
+++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/AAF_Locate.java
@@ -0,0 +1,243 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+
+package org.onap.aaf.auth.locate;
+
+import java.net.URI;
+import java.util.Map;
+
+import javax.servlet.Filter;
+
+import org.onap.aaf.auth.cache.Cache;
+import org.onap.aaf.auth.cache.Cache.Dated;
+import org.onap.aaf.auth.dao.CassAccess;
+import org.onap.aaf.auth.dao.cass.LocateDAO;
+import org.onap.aaf.auth.direct.DirectLocatorCreator;
+import org.onap.aaf.auth.direct.DirectRegistrar;
+import org.onap.aaf.auth.env.AuthzEnv;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.env.AuthzTransFilter;
+import org.onap.aaf.auth.locate.api.API_AAFAccess;
+import org.onap.aaf.auth.locate.api.API_Api;
+import org.onap.aaf.auth.locate.api.API_Find;
+import org.onap.aaf.auth.locate.api.API_Proxy;
+import org.onap.aaf.auth.locate.facade.LocateFacadeFactory;
+import org.onap.aaf.auth.locate.facade.LocateFacade_1_0;
+import org.onap.aaf.auth.locate.mapper.Mapper.API;
+import org.onap.aaf.auth.rserv.HttpMethods;
+import org.onap.aaf.auth.server.AbsService;
+import org.onap.aaf.auth.server.JettyServiceStarter;
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.Locator;
+import org.onap.aaf.cadi.LocatorException;
+import org.onap.aaf.cadi.PropAccess;
+import org.onap.aaf.cadi.aaf.v2_0.AAFAuthn;
+import org.onap.aaf.cadi.aaf.v2_0.AAFConHttp;
+import org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm;
+import org.onap.aaf.cadi.aaf.v2_0.AAFTrustChecker;
+import org.onap.aaf.cadi.aaf.v2_0.AbsAAFLocator;
+import org.onap.aaf.cadi.config.Config;
+import org.onap.aaf.cadi.register.Registrant;
+import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.env.Data;
+import org.onap.aaf.misc.env.Env;
+
+import com.datastax.driver.core.Cluster;
+
+public class AAF_Locate extends AbsService<AuthzEnv, AuthzTrans> {
+ private static final String DOT_LOCATOR = ".locator";
+
+ private static final String USER_PERMS = "userPerms";
+ private LocateFacade_1_0 facade; // this is the default Facade
+ private LocateFacade_1_0 facade_1_0_XML;
+ public Map<String, Dated> cacheUser;
+ public final AAFAuthn<?> aafAuthn;
+ public final AAFLurPerm aafLurPerm;
+ private Locator<URI> gui_locator;
+ public final long expireIn;
+ private final Cluster cluster;
+ public final LocateDAO locateDAO;
+ private Locator<URI> dal;
+ private final String aaf_service_name;
+ private final String aaf_gui_name;
+
+
+ /**
+ * Construct AuthzAPI with all the Context Supporting Routes that Authz needs
+ *
+ * @param env
+ * @param si
+ * @param dm
+ * @param decryptor
+ * @throws APIException
+ */
+ public AAF_Locate(final AuthzEnv env) throws Exception {
+ super(env.access(), env);
+ aaf_service_name = app_name.replace(DOT_LOCATOR, ".service");
+ aaf_gui_name = app_name.replace(DOT_LOCATOR, ".gui");
+
+ expireIn = Long.parseLong(env.getProperty(Config.AAF_USER_EXPIRES, Config.AAF_USER_EXPIRES_DEF));
+
+ // Initialize Facade for all uses
+ AuthzTrans trans = env.newTransNoAvg();
+
+ cluster = org.onap.aaf.auth.dao.CassAccess.cluster(env,null);
+ locateDAO = new LocateDAO(trans,cluster,CassAccess.KEYSPACE);
+
+ // Have AAFLocator object Create DirectLocators for Location needs
+ AbsAAFLocator.setCreator(new DirectLocatorCreator(env, locateDAO));
+
+ aafLurPerm = aafCon().newLur();
+ // Note: If you need both Authn and Authz construct the following:
+ aafAuthn = aafCon().newAuthn(aafLurPerm);
+
+
+ facade = LocateFacadeFactory.v1_0(env,locateDAO,trans,Data.TYPE.JSON); // Default Facade
+ facade_1_0_XML = LocateFacadeFactory.v1_0(env,locateDAO,trans,Data.TYPE.XML);
+
+ synchronized(env) {
+ if(cacheUser == null) {
+ cacheUser = Cache.obtain(USER_PERMS);
+ Cache.startCleansing(env, USER_PERMS);
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Time Critical
+ // These will always be evaluated first
+ ////////////////////////////////////////////////////////////////////////
+ API_AAFAccess.init(this,facade);
+ API_Find.init(this, facade);
+ API_Proxy.init(this, facade);
+
+ ////////////////////////////////////////////////////////////////////////
+ // Management APIs
+ ////////////////////////////////////////////////////////////////////////
+ // There are several APIs around each concept, and it gets a bit too
+ // long in this class to create. The initialization of these Management
+ // APIs have therefore been pushed to StandAlone Classes with static
+ // init functions
+ API_Api.init(this, facade);
+
+ ////////////////////////////////////////////////////////////////////////
+ // Default Function
+ ////////////////////////////////////////////////////////////////////////
+ API_AAFAccess.initDefault(this,facade);
+
+ }
+
+
+ /**
+ * Setup XML and JSON implementations for each supported Version type
+ *
+ * We do this by taking the Code passed in and creating clones of these with the appropriate Facades and properties
+ * to do Versions and Content switches
+ *
+ */
+ public void route(HttpMethods meth, String path, API api, LocateCode code) throws Exception {
+ String version = "1.0";
+ // Get Correct API Class from Mapper
+ Class<?> respCls = facade.mapper().getClass(api);
+ if(respCls==null) throw new Exception("Unknown class associated with " + api.getClass().getName() + ' ' + api.name());
+ // setup Application API HTML ContentTypes for JSON and Route
+ String application = applicationJSON(respCls, version);
+ route(env,meth,path,code,application,"application/json;version="+version,"*/*","*");
+
+ // setup Application API HTML ContentTypes for XML and Route
+ application = applicationXML(respCls, version);
+ route(env,meth,path,code.clone(facade_1_0_XML,false),application,"text/xml;version="+version);
+
+ // Add other Supported APIs here as created
+ }
+
+ public void routeAll(HttpMethods meth, String path, API api, LocateCode code) throws Exception {
+ route(env,meth,path,code,""); // this will always match
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.onap.aaf.auth.server.AbsServer#_newAAFConHttp()
+ */
+ @Override
+ protected AAFConHttp _newAAFConHttp() throws CadiException {
+ try {
+ if(dal==null) {
+ dal = AbsAAFLocator.create(aaf_service_name,Config.AAF_DEFAULT_VERSION);
+ }
+ // utilize pre-constructed DirectAAFLocator
+ return new AAFConHttp(env.access(),dal);
+ } catch (APIException | LocatorException e) {
+ throw new CadiException(e);
+ }
+
+ }
+
+ public Locator<URI> getGUILocator() throws LocatorException {
+ if(gui_locator==null) {
+ gui_locator = AbsAAFLocator.create(aaf_gui_name,Config.AAF_DEFAULT_VERSION);
+ }
+ return gui_locator;
+ }
+
+
+ @Override
+ public Filter[] filters() throws CadiException, LocatorException {
+ try {
+ return new Filter[] {
+ new AuthzTransFilter(env, aafCon(),
+ new AAFTrustChecker((Env)env)
+ )};
+ } catch (NumberFormatException e) {
+ throw new CadiException("Invalid Property information", e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Registrant<AuthzEnv>[] registrants(final int port) throws CadiException {
+ return new Registrant[] {
+ new DirectRegistrar(access,locateDAO,app_name,app_version,port)
+ };
+ }
+
+ @Override
+ public void destroy() {
+ Cache.stopTimer();
+ if(cluster!=null) {
+ cluster.close();
+ }
+ super.destroy();
+ }
+
+ public static void main(final String[] args) {
+ PropAccess propAccess = new PropAccess(args);
+ try {
+ AAF_Locate service = new AAF_Locate(new AuthzEnv(propAccess));
+// service.env().setLog4JNames("log4j.properties","authz","gw","audit","init","trace");
+ JettyServiceStarter<AuthzEnv,AuthzTrans> jss = new JettyServiceStarter<AuthzEnv,AuthzTrans>(service);
+ jss.start();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/BasicAuthCode.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/BasicAuthCode.java
new file mode 100644
index 00000000..ac348f3f
--- /dev/null
+++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/BasicAuthCode.java
@@ -0,0 +1,77 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.auth.locate;
+
+import java.security.Principal;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpStatus;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.locate.facade.LocateFacade;
+import org.onap.aaf.cadi.Symm;
+import org.onap.aaf.cadi.aaf.v2_0.AAFAuthn;
+import org.onap.aaf.cadi.principal.BasicPrincipal;
+import org.onap.aaf.cadi.principal.X509Principal;
+
+public class BasicAuthCode extends LocateCode {
+ private AAFAuthn<?> authn;
+
+ public BasicAuthCode(AAFAuthn<?> authn, LocateFacade facade) {
+ super(facade, "AAF Basic Auth",true);
+ this.authn = authn;
+ }
+
+ @Override
+ public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+ Principal p = trans.getUserPrincipal();
+ if(p == null) {
+ trans.error().log("Transaction not Authenticated... no Principal");
+ } else if (p instanceof BasicPrincipal) {
+ // the idea is that if call is made with this credential, and it's a BasicPrincipal, it's ok
+ // otherwise, it wouldn't have gotten here.
+ resp.setStatus(HttpStatus.OK_200);
+ return;
+ } else if (p instanceof X509Principal) {
+ // Since X509Principal has priority, BasicAuth Info might be there, but not validated.
+ String ba;
+ if((ba=req.getHeader("Authorization"))!=null && ba.startsWith("Basic ")) {
+ ba = Symm.base64noSplit.decode(ba.substring(6));
+ int colon = ba.indexOf(':');
+ if(colon>=0) {
+ String err;
+ if((err=authn.validate(ba.substring(0, colon), ba.substring(colon+1),trans))==null) {
+ resp.setStatus(HttpStatus.OK_200);
+ } else {
+ trans.audit().log(ba.substring(0,colon),": ",err);
+ resp.setStatus(HttpStatus.UNAUTHORIZED_401);
+ }
+ return;
+ }
+ }
+ }
+ trans.checkpoint("Basic Auth Check Failed: This wasn't a Basic Auth Trans");
+ // For Auth Security questions, we don't give any info to client on why failed
+ resp.setStatus(HttpStatus.FORBIDDEN_403);
+ }
+}
diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/LocateCode.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/LocateCode.java
new file mode 100644
index 00000000..b1aa23cc
--- /dev/null
+++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/LocateCode.java
@@ -0,0 +1,44 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.auth.locate;
+
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.locate.facade.LocateFacade;
+import org.onap.aaf.auth.rserv.HttpCode;
+
+public abstract class LocateCode extends HttpCode<AuthzTrans, LocateFacade> implements Cloneable {
+ public boolean useJSON;
+
+ public LocateCode(LocateFacade facade, String description, boolean useJSON, String ... roles) {
+ super(facade, description, roles);
+ this.useJSON = useJSON;
+ }
+
+ public <D extends LocateCode> D clone(LocateFacade facade, boolean useJSON) throws Exception {
+ @SuppressWarnings("unchecked")
+ D d = (D)clone();
+ d.useJSON = useJSON;
+ d.context = facade;
+ return d;
+ }
+
+} \ No newline at end of file
diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_AAFAccess.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_AAFAccess.java
new file mode 100644
index 00000000..9de92d14
--- /dev/null
+++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_AAFAccess.java
@@ -0,0 +1,259 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.auth.locate.api;
+
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.URI;
+import java.security.Principal;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpStatus;
+import org.onap.aaf.auth.cache.Cache.Dated;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.auth.locate.AAF_Locate;
+import org.onap.aaf.auth.locate.BasicAuthCode;
+import org.onap.aaf.auth.locate.LocateCode;
+import org.onap.aaf.auth.locate.facade.LocateFacade;
+import org.onap.aaf.auth.locate.mapper.Mapper.API;
+import org.onap.aaf.auth.rserv.HttpMethods;
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.Locator;
+import org.onap.aaf.cadi.Locator.Item;
+import org.onap.aaf.cadi.LocatorException;
+import org.onap.aaf.cadi.aaf.AAFPermission;
+import org.onap.aaf.cadi.client.Future;
+import org.onap.aaf.cadi.client.Rcli;
+import org.onap.aaf.cadi.client.Retryable;
+import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.env.Env;
+import org.onap.aaf.misc.env.TimeTaken;
+
+public class API_AAFAccess {
+// private static String service, version, envContext;
+
+ private static final String GET_PERMS_BY_USER = "Get Perms by User";
+ private static final String USER_HAS_PERM ="User Has Perm";
+// private static final String USER_IN_ROLE ="User Has Role";
+
+ /**
+ * Normal Init level APIs
+ *
+ * @param gwAPI
+ * @param facade
+ * @throws Exception
+ */
+ public static void init(final AAF_Locate gwAPI, LocateFacade facade) throws Exception {
+
+
+ gwAPI.route(HttpMethods.GET,"/authz/perms/user/:user",API.VOID,new LocateCode(facade,GET_PERMS_BY_USER, true) {
+ @Override
+ public void handle(final AuthzTrans trans, final HttpServletRequest req, final HttpServletResponse resp) throws Exception {
+ TimeTaken tt = trans.start(GET_PERMS_BY_USER, Env.SUB);
+ try {
+ final String accept = req.getHeader("ACCEPT");
+ final String user = pathParam(req,":user");
+ if(!user.contains("@")) {
+ context.error(trans,resp,Result.ERR_BadData,"User [%s] must be fully qualified with domain",user);
+ return;
+ }
+ final String key = trans.user() + user + (accept!=null&&accept.contains("xml")?"-xml":"-json");
+ TimeTaken tt2 = trans.start("Cache Lookup",Env.SUB);
+ Dated d;
+ try {
+ d = gwAPI.cacheUser.get(key);
+ } finally {
+ tt2.done();
+ }
+
+ if(d==null || d.data.isEmpty()) {
+ tt2 = trans.start("AAF Service Call",Env.REMOTE);
+ try {
+ gwAPI.clientAsUser(trans.getUserPrincipal(), new Retryable<Void>() {
+ @Override
+ public Void code(Rcli<?> client) throws CadiException, ConnectException, APIException {
+ Future<String> fp = client.read("/authz/perms/user/"+user,accept);
+ if(fp.get(5000)) {
+ gwAPI.cacheUser.put(key, new Dated(new User(fp.code(),fp.body()),gwAPI.expireIn));
+ resp.setStatus(HttpStatus.OK_200);
+ ServletOutputStream sos;
+ try {
+ sos = resp.getOutputStream();
+ sos.print(fp.value);
+ } catch (IOException e) {
+ throw new CadiException(e);
+ }
+ } else {
+ gwAPI.cacheUser.put(key, new Dated(new User(fp.code(),fp.body()),gwAPI.expireIn));
+ context.error(trans,resp,fp.code(),fp.body());
+ }
+ return null;
+ }
+ });
+ } finally {
+ tt2.done();
+ }
+ } else {
+ User u = (User)d.data.get(0);
+ resp.setStatus(u.code);
+ ServletOutputStream sos = resp.getOutputStream();
+ sos.print(u.resp);
+ }
+ } finally {
+ tt.done();
+ }
+ }
+ });
+
+
+ gwAPI.route(gwAPI.env,HttpMethods.GET,"/authn/basicAuth",new BasicAuthCode(gwAPI.aafAuthn,facade)
+ ,"text/plain","*/*","*");
+
+ /**
+ * Query User Has Perm
+ */
+ gwAPI.route(HttpMethods.GET,"/ask/:user/has/:type/:instance/:action",API.VOID,new LocateCode(facade,USER_HAS_PERM, true) {
+ @Override
+ public void handle(final AuthzTrans trans, final HttpServletRequest req, HttpServletResponse resp) throws Exception {
+ try {
+ resp.getOutputStream().print(
+ gwAPI.aafLurPerm.fish(new Principal() {
+ public String getName() {
+ return pathParam(req,":user");
+ };
+ }, new AAFPermission(
+ pathParam(req,":type"),
+ pathParam(req,":instance"),
+ pathParam(req,":action"))));
+ resp.setStatus(HttpStatus.OK_200);
+ } catch(Exception e) {
+ context.error(trans, resp, Result.ERR_General, e.getMessage());
+ }
+ }
+ });
+
+ gwAPI.route(HttpMethods.GET,"/gui/:path*",API.VOID,new LocateCode(facade,"Short Access PROD GUI for AAF", true) {
+ @Override
+ public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+ try {
+ redirect(trans, req, resp, context,
+ gwAPI.getGUILocator(),
+ "gui/"+pathParam(req,":path"));
+ } catch (LocatorException e) {
+ context.error(trans, resp, Result.ERR_BadData, e.getMessage());
+ } catch (Exception e) {
+ context.error(trans, resp, Result.ERR_General, e.getMessage());
+ }
+ }
+ });
+
+ gwAPI.route(HttpMethods.GET,"/aaf/:version/:path*",API.VOID,new LocateCode(facade,"Access PROD GUI for AAF", true) {
+ @Override
+ public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+ try {
+ redirect(trans, req, resp, context,
+ gwAPI.getGUILocator(),
+ pathParam(req,":path"));
+ } catch (LocatorException e) {
+ context.error(trans, resp, Result.ERR_BadData, e.getMessage());
+ } catch (Exception e) {
+ context.error(trans, resp, Result.ERR_General, e.getMessage());
+ }
+ }
+ });
+ }
+
+ public static void initDefault(final AAF_Locate gwAPI, LocateFacade facade) throws Exception {
+
+ /**
+ * "login" url
+ */
+ gwAPI.route(HttpMethods.GET,"/login",API.VOID,new LocateCode(facade,"Access Login GUI for AAF", true) {
+ @Override
+ public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+ try {
+ redirect(trans, req, resp, context,
+ gwAPI.getGUILocator(),
+ "login");
+ } catch (LocatorException e) {
+ context.error(trans, resp, Result.ERR_BadData, e.getMessage());
+ } catch (Exception e) {
+ context.error(trans, resp, Result.ERR_General, e.getMessage());
+ }
+ }
+ });
+
+
+ /**
+ * Default URL
+ */
+ gwAPI.route(HttpMethods.GET,"/",API.VOID,new LocateCode(facade,"Access GUI for AAF", true) {
+ @Override
+ public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+ try {
+ redirect(trans, req, resp, context,
+ gwAPI.getGUILocator(),
+ "gui/home");
+ } catch (Exception e) {
+ context.error(trans, resp, Result.ERR_General, e.getMessage());
+ }
+ }
+ });
+ }
+
+ private static void redirect(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp, LocateFacade context, Locator<URI> loc, String path) throws IOException {
+ try {
+ if(loc.hasItems()) {
+ Item item = loc.best();
+ URI uri = loc.get(item);
+ StringBuilder redirectURL = new StringBuilder(uri.toString());
+ redirectURL.append('/');
+ redirectURL.append(path);
+ String str = req.getQueryString();
+ if(str!=null) {
+ redirectURL.append('?');
+ redirectURL.append(str);
+ }
+ trans.info().log("Redirect to",redirectURL);
+ resp.sendRedirect(redirectURL.toString());
+ } else {
+ context.error(trans, resp, Result.err(Result.ERR_NotFound,"No Locations found for redirection"));
+ }
+ } catch (LocatorException e) {
+ context.error(trans, resp, Result.err(Result.ERR_NotFound,"No Endpoints found for %s",req.getPathInfo()));
+ }
+ }
+
+ private static class User {
+ public final int code;
+ public final String resp;
+
+ public User(int code, String resp) {
+ this.code = code;
+ this.resp = resp;
+ }
+ }
+}
diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Api.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Api.java
new file mode 100644
index 00000000..8e3fab56
--- /dev/null
+++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Api.java
@@ -0,0 +1,97 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.auth.locate.api;
+
+import static org.onap.aaf.auth.layer.Result.OK;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpStatus;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.auth.locate.AAF_Locate;
+import org.onap.aaf.auth.locate.LocateCode;
+import org.onap.aaf.auth.locate.facade.LocateFacade;
+import org.onap.aaf.auth.locate.mapper.Mapper.API;
+import org.onap.aaf.auth.rserv.HttpMethods;
+import org.onap.aaf.cadi.Symm;
+
+/**
+ * API Apis
+ * @author Jonathan
+ *
+ */
+public class API_Api {
+ /**
+ * Normal Init level APIs
+ *
+ * @param gwAPI
+ * @param facade
+ * @throws Exception
+ */
+ public static void init(final AAF_Locate gwAPI, LocateFacade facade) throws Exception {
+ ////////
+ // Overall APIs
+ ///////
+ gwAPI.route(HttpMethods.GET,"/api",API.VOID,new LocateCode(facade,"Document API", true) {
+ @Override
+ public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+ Result<Void> r = context.getAPI(trans,resp,gwAPI);
+ switch(r.status) {
+ case OK:
+ resp.setStatus(HttpStatus.OK_200);
+ break;
+ default:
+ context.error(trans,resp,r);
+ }
+
+ }
+ });
+
+ ////////
+ // Overall Examples
+ ///////
+ gwAPI.route(HttpMethods.GET,"/api/example/*",API.VOID,new LocateCode(facade,"Document API", true) {
+ @Override
+ public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+ String pathInfo = req.getPathInfo();
+ int question = pathInfo.lastIndexOf('?');
+
+ pathInfo = pathInfo.substring(13, question<0?pathInfo.length():question);// IMPORTANT, this is size of "/api/example/"
+ String nameOrContextType=Symm.base64noSplit.decode(pathInfo);
+// String param = req.getParameter("optional");
+ Result<Void> r = context.getAPIExample(trans,resp,nameOrContextType,
+ question>=0 && "optional=true".equalsIgnoreCase(req.getPathInfo().substring(question+1))
+ );
+ switch(r.status) {
+ case OK:
+ resp.setStatus(HttpStatus.OK_200);
+ break;
+ default:
+ context.error(trans,resp,r);
+ }
+ }
+ });
+
+ }
+}
diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Find.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Find.java
new file mode 100644
index 00000000..27bd8c3a
--- /dev/null
+++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Find.java
@@ -0,0 +1,132 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.auth.locate.api;
+
+import static org.onap.aaf.auth.layer.Result.OK;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpStatus;
+import org.onap.aaf.auth.common.Define;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.auth.locate.AAF_Locate;
+import org.onap.aaf.auth.locate.LocateCode;
+import org.onap.aaf.auth.locate.facade.LocateFacade;
+import org.onap.aaf.auth.locate.mapper.Mapper.API;
+import org.onap.aaf.auth.rserv.HttpMethods;
+import org.onap.aaf.misc.env.util.Split;
+
+/**
+ * API Apis.. using Redirect for mechanism
+ *
+ * @author Jonathan
+ *
+ */
+public class API_Find {
+ /**
+ * Normal Init level APIs
+ *
+ * @param gwAPI
+ * @param facade
+ * @throws Exception
+ */
+ public static void init(final AAF_Locate gwAPI, LocateFacade facade) throws Exception {
+ ////////
+ // Overall APIs
+ ///////
+
+ final LocateCode locationInfo = new LocateCode(facade,"Location Information", true) {
+ @Override
+ public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+ String service = pathParam(req, ":service");
+ String version = pathParam(req, ":version");
+ String other = pathParam(req, ":other");
+ if(service.indexOf(':')>=0) {
+ String split[] = Split.split(':', service);
+ switch(split.length) {
+ case 3:
+ other=split[2];
+ case 2:
+ version = split[1];
+ service = split[0];
+ }
+ }
+ service=Define.varReplace(service);
+ Result<Void> r = context.getEndpoints(trans,resp,
+ req.getPathInfo(), // use as Key
+ service,version,other
+ );
+ switch(r.status) {
+ case OK:
+ resp.setStatus(HttpStatus.OK_200);
+ break;
+ default:
+ context.error(trans,resp,r);
+ }
+ }
+ };
+
+ gwAPI.route(HttpMethods.GET,"/locate/:service/:version",API.ENDPOINTS,locationInfo);
+ gwAPI.route(HttpMethods.GET,"/locate/:service/:version/:other",API.ENDPOINTS,locationInfo);
+ gwAPI.route(HttpMethods.GET,"/locate/:service",API.ENDPOINTS,locationInfo);
+
+
+ gwAPI.route(HttpMethods.GET,"/download/agent", API.VOID, new LocateCode(facade,"Redirect to latest Agent",false) {
+ @Override
+ public void handle(AuthzTrans arg0, HttpServletRequest arg1, HttpServletResponse arg2) throws Exception {
+ }
+ });
+
+ gwAPI.route(HttpMethods.PUT,"/registration",API.MGMT_ENDPOINTS,new LocateCode(facade,"Put Location Information", true) {
+ @Override
+ public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+ Result<Void> r = context.putMgmtEndpoints(trans,req,resp);
+ switch(r.status) {
+ case OK:
+ resp.setStatus(HttpStatus.OK_200);
+ break;
+ default:
+ context.error(trans,resp,r);
+ }
+
+ }
+ });
+
+ gwAPI.route(HttpMethods.DELETE,"/registration",API.MGMT_ENDPOINTS,new LocateCode(facade,"Remove Location Information", true) {
+ @Override
+ public void handle(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) throws Exception {
+ Result<Void> r = context.removeMgmtEndpoints(trans,req,resp);
+ switch(r.status) {
+ case OK:
+ resp.setStatus(HttpStatus.OK_200);
+ break;
+ default:
+ context.error(trans,resp,r);
+ }
+
+ }
+ });
+
+ }
+}
diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Proxy.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Proxy.java
new file mode 100644
index 00000000..d2e4583c
--- /dev/null
+++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/api/API_Proxy.java
@@ -0,0 +1,163 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.auth.locate.api;
+
+import java.net.ConnectException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpStatus;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.locate.AAF_Locate;
+import org.onap.aaf.auth.locate.BasicAuthCode;
+import org.onap.aaf.auth.locate.LocateCode;
+import org.onap.aaf.auth.locate.facade.LocateFacade;
+import org.onap.aaf.auth.locate.mapper.Mapper.API;
+import org.onap.aaf.auth.rserv.HttpMethods;
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.client.Future;
+import org.onap.aaf.cadi.client.Rcli;
+import org.onap.aaf.cadi.client.Retryable;
+import org.onap.aaf.cadi.config.Config;
+import org.onap.aaf.cadi.oauth.OAuth2Principal;
+import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.env.Env;
+import org.onap.aaf.misc.env.TimeTaken;
+
+/**
+ * API Apis.. using Redirect for mechanism
+ *
+ * @author Jonathan
+ *
+ */
+public class API_Proxy {
+
+ /**
+ * Normal Init level APIs
+ *
+ * @param gwAPI
+ * @param facade
+ * @throws Exception
+ */
+ public static void init(final AAF_Locate gwAPI, LocateFacade facade) throws Exception {
+
+ String aafurl = gwAPI.access.getProperty(Config.AAF_URL,null);
+ if(aafurl==null) {
+ } else {
+ ////////
+ // Transferring APIs
+ // But DO NOT transfer BasicAuth case... wastes resources.
+ ///////
+ final BasicAuthCode bac = new BasicAuthCode(gwAPI.aafAuthn,facade);
+
+ gwAPI.routeAll(HttpMethods.GET,"/proxy/:path*",API.VOID,new LocateCode(facade,"Proxy GET", true) {
+ @Override
+ public void handle(final AuthzTrans trans, final HttpServletRequest req, final HttpServletResponse resp) throws Exception {
+ if("/proxy/authn/basicAuth".equals(req.getPathInfo()) && !(req.getUserPrincipal() instanceof OAuth2Principal)) {
+ bac.handle(trans, req, resp);
+ } else {
+ TimeTaken tt = trans.start("Forward to AAF Service", Env.REMOTE);
+ try {
+ gwAPI.clientAsUser(trans.getUserPrincipal(), new Retryable<Void>() {
+ @Override
+ public Void code(Rcli<?> client) throws CadiException, ConnectException, APIException {
+ Future<Void> ft = client.transfer(req,resp,pathParam(req, ":path"),HttpStatus.OK_200);
+ ft.get(10000); // Covers return codes and err messages
+ return null;
+ }
+ });
+
+ } catch (CadiException | APIException e) {
+ trans.error().log(e);
+ } finally {
+ tt.done();
+ }
+ }
+ }
+ });
+
+ gwAPI.routeAll(HttpMethods.POST,"/proxy/:path*",API.VOID,new LocateCode(facade,"Proxy POST", true) {
+ @Override
+ public void handle(final AuthzTrans trans, final HttpServletRequest req, final HttpServletResponse resp) throws Exception {
+ TimeTaken tt = trans.start("Forward to AAF Service", Env.REMOTE);
+ try {
+ gwAPI.clientAsUser(trans.getUserPrincipal(), new Retryable<Void>() {
+ @Override
+ public Void code(Rcli<?> client) throws CadiException, ConnectException, APIException {
+ Future<Void> ft = client.transfer(req,resp,pathParam(req, ":path"),HttpStatus.CREATED_201);
+ ft.get(10000); // Covers return codes and err messages
+ return null;
+ }
+ });
+ } catch (CadiException | APIException e) {
+ trans.error().log(e);
+ } finally {
+ tt.done();
+ }
+ }
+ });
+
+ gwAPI.routeAll(HttpMethods.PUT,"/proxy/:path*",API.VOID,new LocateCode(facade,"Proxy PUT", true) {
+ @Override
+ public void handle(final AuthzTrans trans, final HttpServletRequest req, final HttpServletResponse resp) throws Exception {
+ TimeTaken tt = trans.start("Forward to AAF Service", Env.REMOTE);
+ try {
+ gwAPI.clientAsUser(trans.getUserPrincipal(), new Retryable<Void>() {
+ @Override
+ public Void code(Rcli<?> client) throws CadiException, ConnectException, APIException {
+ Future<Void> ft = client.transfer(req,resp,pathParam(req, ":path"),HttpStatus.OK_200);
+ ft.get(10000); // Covers return codes and err messages
+ return null;
+ }
+ });
+ } catch (CadiException | APIException e) {
+ trans.error().log(e);
+ } finally {
+ tt.done();
+ }
+ }
+ });
+
+ gwAPI.routeAll(HttpMethods.DELETE,"/proxy/:path*",API.VOID,new LocateCode(facade,"Proxy DELETE", true) {
+ @Override
+ public void handle(final AuthzTrans trans, final HttpServletRequest req, final HttpServletResponse resp) throws Exception {
+ TimeTaken tt = trans.start("Forward to AAF Service", Env.REMOTE);
+ try {
+ gwAPI.clientAsUser(trans.getUserPrincipal(), new Retryable<Void>() {
+ @Override
+ public Void code(Rcli<?> client) throws CadiException, ConnectException, APIException {
+ Future<Void> ft = client.transfer(req,resp,pathParam(req, ":path"),HttpStatus.OK_200);
+ ft.get(10000); // Covers return codes and err messages
+ return null;
+ }
+ });
+ } catch (CadiException | APIException e) {
+ trans.error().log(e);
+ } finally {
+ tt.done();
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacade.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacade.java
new file mode 100644
index 00000000..817fcc58
--- /dev/null
+++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacade.java
@@ -0,0 +1,106 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.auth.locate.facade;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.auth.rserv.RServlet;
+
+
+/**
+ *
+ * @author Jonathan
+ *
+ */
+public interface LocateFacade {
+
+///////////////////// STANDARD ELEMENTS //////////////////
+ /**
+ * @param trans
+ * @param response
+ * @param result
+ */
+ void error(AuthzTrans trans, HttpServletResponse response, Result<?> result);
+
+ /**
+ *
+ * @param trans
+ * @param response
+ * @param status
+ */
+ void error(AuthzTrans trans, HttpServletResponse response, int status, String msg, String ... detail);
+
+
+ /**
+ *
+ * @param trans
+ * @param resp
+ * @param rservlet
+ * @return
+ */
+ public Result<Void> getAPI(AuthzTrans trans, HttpServletResponse resp, RServlet<AuthzTrans> rservlet);
+
+ /**
+ *
+ * @param trans
+ * @param resp
+ * @param typeCode
+ * @param optional
+ * @return
+ */
+ public abstract Result<Void> getAPIExample(AuthzTrans trans, HttpServletResponse resp, String typeCode, boolean optional);
+
+ /**
+ *
+ * @param trans
+ * @param resp
+ * @param service
+ * @param version
+ * @param other
+ * @param string
+ * @return
+ */
+ public abstract Result<Void> getEndpoints(AuthzTrans trans, HttpServletResponse resp, String key,
+ String service, String version, String other);
+
+ /**
+ *
+ * @param trans
+ * @param req
+ * @param resp
+ * @return
+ */
+ public abstract Result<Void> putMgmtEndpoints(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp);
+
+ /**
+ *
+ * @param trans
+ * @param req
+ * @param resp
+ * @return
+ */
+ public abstract Result<Void> removeMgmtEndpoints(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp);
+
+} \ No newline at end of file
diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacadeFactory.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacadeFactory.java
new file mode 100644
index 00000000..ea20df5a
--- /dev/null
+++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacadeFactory.java
@@ -0,0 +1,48 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.auth.locate.facade;
+
+import org.onap.aaf.auth.dao.cass.LocateDAO;
+import org.onap.aaf.auth.env.AuthzEnv;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.locate.mapper.Mapper_1_0;
+import org.onap.aaf.auth.locate.service.LocateServiceImpl;
+import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.env.Data;
+
+import locate_local.v1_0.Error;
+import locate_local.v1_0.InRequest;
+import locate_local.v1_0.Out;
+
+
+public class LocateFacadeFactory {
+ public static LocateFacade_1_0 v1_0(AuthzEnv env, LocateDAO locateDAO, AuthzTrans trans, Data.TYPE type) throws APIException {
+ return new LocateFacade_1_0(
+ env,
+ new LocateServiceImpl<
+ InRequest,
+ Out,
+ Error>(trans,locateDAO,new Mapper_1_0()),
+ type);
+ }
+
+}
diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacadeImpl.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacadeImpl.java
new file mode 100644
index 00000000..1ce9821f
--- /dev/null
+++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacadeImpl.java
@@ -0,0 +1,393 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.auth.locate.facade;
+
+
+import static org.onap.aaf.auth.layer.Result.ERR_ActionNotCompleted;
+import static org.onap.aaf.auth.layer.Result.ERR_BadData;
+import static org.onap.aaf.auth.layer.Result.ERR_ConflictAlreadyExists;
+import static org.onap.aaf.auth.layer.Result.ERR_Denied;
+import static org.onap.aaf.auth.layer.Result.ERR_NotFound;
+import static org.onap.aaf.auth.layer.Result.ERR_NotImplemented;
+import static org.onap.aaf.auth.layer.Result.ERR_Policy;
+import static org.onap.aaf.auth.layer.Result.ERR_Security;
+import static org.onap.aaf.auth.layer.Result.OK;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.onap.aaf.auth.dao.cass.Status;
+import org.onap.aaf.auth.env.AuthzEnv;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.layer.FacadeImpl;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.auth.locate.mapper.Mapper;
+import org.onap.aaf.auth.locate.mapper.Mapper.API;
+import org.onap.aaf.auth.locate.service.LocateService;
+import org.onap.aaf.auth.locate.service.LocateServiceImpl;
+import org.onap.aaf.auth.rserv.RServlet;
+import org.onap.aaf.auth.rserv.RouteReport;
+import org.onap.aaf.auth.rserv.doc.ApiDoc;
+import org.onap.aaf.cadi.aaf.client.Examples;
+import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.env.Data;
+import org.onap.aaf.misc.env.Env;
+import org.onap.aaf.misc.env.TimeTaken;
+import org.onap.aaf.misc.env.Data.TYPE;
+import org.onap.aaf.misc.rosetta.env.RosettaDF;
+import org.onap.aaf.misc.rosetta.env.RosettaData;
+
+import locate_local.v1_0.Api;
+
+/**
+ * AuthzFacade
+ *
+ * This Service Facade encapsulates the essence of the API Service can do, and provides
+ * a single created object for elements such as RosettaDF.
+ *
+ * The Responsibilities of this class are to:
+ * 1) Interact with the Service Implementation (which might be supported by various kinds of Backend Storage)
+ * 2) Validate incoming data (if applicable)
+ * 3) Convert the Service response into the right Format, and mark the Content Type
+ * a) In the future, we may support multiple Response Formats, aka JSON or XML, based on User Request.
+ * 4) Log Service info, warnings and exceptions as necessary
+ * 5) When asked by the API layer, this will create and write Error content to the OutputStream
+ *
+ * Note: This Class does NOT set the HTTP Status Code. That is up to the API layer, so that it can be
+ * clearly coordinated with the API Documentation
+ *
+ * @author Jonathan
+ *
+ */
+public abstract class LocateFacadeImpl<IN,OUT,ENDPOINTS,MGMT_ENDPOINTS,ERROR> extends FacadeImpl implements LocateFacade
+ {
+ private LocateService<IN,OUT,ENDPOINTS,MGMT_ENDPOINTS,ERROR> service;
+
+ private final RosettaDF<ERROR> errDF;
+ private final RosettaDF<Api> apiDF;
+ private final RosettaDF<ENDPOINTS> epDF;
+ private final RosettaDF<MGMT_ENDPOINTS> mepDF;
+
+
+ private static long cacheClear = 0L, emptyCheck=0L;
+ private final static Map<String,String> epsCache = new HashMap<String, String>(); // protected manually, in getEndpoints
+
+ public LocateFacadeImpl(AuthzEnv env, LocateService<IN,OUT,ENDPOINTS,MGMT_ENDPOINTS,ERROR> service, Data.TYPE dataType) throws APIException {
+ this.service = service;
+ (errDF = env.newDataFactory(mapper().getClass(API.ERROR))).in(dataType).out(dataType);
+ (apiDF = env.newDataFactory(Api.class)).in(dataType).out(dataType);
+ (epDF = env.newDataFactory(mapper().getClass(API.ENDPOINTS))).in(dataType).out(dataType);
+ (mepDF = env.newDataFactory(mapper().getClass(API.MGMT_ENDPOINTS))).in(dataType).out(dataType);
+ }
+
+ public Mapper<IN,OUT,ENDPOINTS,MGMT_ENDPOINTS,ERROR> mapper() {
+ return service.mapper();
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.authz.facade.AuthzFacade#error(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletResponse, int)
+ *
+ * Note: Conforms to AT&T TSS RESTful Error Structure
+ */
+ @Override
+ public void error(AuthzTrans trans, HttpServletResponse response, Result<?> result) {
+ String msg = result.details==null?"":result.details.trim();
+ String[] detail;
+ if(result.variables==null) {
+ detail = new String[1];
+ } else {
+ int l = result.variables.length;
+ detail=new String[l+1];
+ System.arraycopy(result.variables, 0, detail, 1, l);
+ }
+ error(trans, response, result.status,msg,detail);
+ }
+
+ @Override
+ public void error(AuthzTrans trans, HttpServletResponse response, int status, String msg, String ... _detail) {
+ String[] detail = _detail;
+ if(detail.length==0) {
+ detail=new String[1];
+ }
+ boolean hidemsg = false;
+ String msgId;
+ switch(status) {
+ case 202:
+ case ERR_ActionNotCompleted:
+ msgId = "SVC1202";
+ detail[0] = "Accepted, Action not complete";
+ response.setStatus(/*httpstatus=*/202);
+ break;
+
+ case 403:
+ case ERR_Policy:
+ case ERR_Security:
+ case ERR_Denied:
+ msgId = "SVC1403";
+ detail[0] = "Forbidden";
+ response.setStatus(/*httpstatus=*/403);
+ break;
+
+ case 404:
+ case ERR_NotFound:
+ msgId = "SVC1404";
+ detail[0] = "Not Found";
+ response.setStatus(/*httpstatus=*/404);
+ break;
+
+ case 406:
+ case ERR_BadData:
+ msgId="SVC1406";
+ detail[0] = "Not Acceptable";
+ response.setStatus(/*httpstatus=*/406);
+ break;
+
+ case 409:
+ case ERR_ConflictAlreadyExists:
+ msgId = "SVC1409";
+ detail[0] = "Conflict Already Exists";
+ response.setStatus(/*httpstatus=*/409);
+ break;
+
+ case 501:
+ case ERR_NotImplemented:
+ msgId = "SVC1501";
+ detail[0] = "Not Implemented";
+ response.setStatus(/*httpstatus=*/501);
+ break;
+
+ default:
+ msgId = "SVC1500";
+ detail[0] = "General Service Error";
+ response.setStatus(/*httpstatus=*/500);
+ hidemsg = true;
+ break;
+ }
+
+ try {
+ StringBuilder holder = new StringBuilder();
+ ERROR em = mapper().errorFromMessage(holder,msgId,msg,detail);
+ trans.checkpoint(
+ "ErrResp [" +
+ msgId +
+ "] " +
+ holder.toString(),
+ Env.ALWAYS);
+ if(hidemsg) {
+ holder.setLength(0);
+ em = mapper().errorFromMessage(holder, msgId, "Server had an issue processing this request");
+ }
+ errDF.newData(trans).load(em).to(response.getOutputStream());
+
+ } catch (Exception e) {
+ trans.error().log(e,"unable to send response for",msg);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.authz.facade.AuthzFacade#getAPI(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletResponse)
+ */
+ public final static String API_REPORT = "apiReport";
+ @Override
+ public Result<Void> getAPI(AuthzTrans trans, HttpServletResponse resp, RServlet<AuthzTrans> rservlet) {
+ TimeTaken tt = trans.start(API_REPORT, Env.SUB);
+ try {
+ Api api = new Api();
+ Api.Route ar;
+ Method[] meths = LocateServiceImpl.class.getDeclaredMethods();
+ for(RouteReport rr : rservlet.routeReport()) {
+ api.getRoute().add(ar = new Api.Route());
+ ar.setMeth(rr.meth.name());
+ ar.setPath(rr.path);
+ ar.setDesc(rr.desc);
+ ar.getContentType().addAll(rr.contextTypes);
+ for(Method m : meths) {
+ ApiDoc ad;
+ if((ad = m.getAnnotation(ApiDoc.class))!=null &&
+ rr.meth.equals(ad.method()) &&
+ rr.path.equals(ad.path())) {
+ for(String param : ad.params()) {
+ ar.getParam().add(param);
+ }
+ for(String text : ad.text()) {
+ ar.getComments().add(text);
+ }
+ ar.setExpected(ad.expectedCode());
+ for(int ec : ad.errorCodes()) {
+ ar.getExplicitErr().add(ec);
+ }
+ }
+ }
+ }
+ apiDF.newData(trans).load(api).to(resp.getOutputStream());
+ setContentType(resp,apiDF.getOutType());
+ return Result.ok();
+
+ } catch (Exception e) {
+ trans.error().log(e,IN,API_REPORT);
+ return Result.err(e);
+ } finally {
+ tt.done();
+ }
+ }
+
+ public final static String API_EXAMPLE = "apiExample";
+ /* (non-Javadoc)
+ * @see com.att.authz.facade.AuthzFacade#getAPIExample(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletResponse, java.lang.String)
+ */
+ @Override
+ public Result<Void> getAPIExample(AuthzTrans trans, HttpServletResponse resp, String nameOrContentType, boolean optional) {
+ TimeTaken tt = trans.start(API_EXAMPLE, Env.SUB);
+ try {
+ String content =Examples.print(apiDF.getEnv(), nameOrContentType, optional);
+ resp.getOutputStream().print(content);
+ setContentType(resp,content.contains("<?xml")?TYPE.XML:TYPE.JSON);
+ return Result.ok();
+ } catch (Exception e) {
+ trans.error().log(e,IN,API_EXAMPLE);
+ return Result.err(Result.ERR_NotImplemented,e.getMessage());
+ } finally {
+ tt.done();
+ }
+ }
+
+ public final static String GET_ENDPOINTS = "getEndpoints";
+ /* (non-Javadoc)
+ * @see org.onap.aaf.auth.locate.facade.GwFacade#getEndpoints(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletResponse, java.lang.String, java.lang.String, java.lang.String)
+ */
+ @Override
+ public Result<Void> getEndpoints(AuthzTrans trans, HttpServletResponse resp, String key, String service, String version, String other) {
+ TimeTaken tt = trans.start(GET_ENDPOINTS, Env.SUB);
+ try {
+ String output=null;
+ long temp=System.currentTimeMillis();
+ synchronized(GET_ENDPOINTS) {
+ if(cacheClear<temp) {
+ epsCache.clear();
+ cacheClear = temp+1000*60*2; // 2 mins standard cache clear
+ } else {
+ output = epsCache.get(key);
+ if("{}".equals(output) && emptyCheck<temp) {
+ output = null;
+ emptyCheck = temp+5000; // 5 second check
+ }
+ }
+ }
+ if(output==null) {
+ Result<ENDPOINTS> reps = this.service.getEndPoints(trans,service,version,other);
+ if(reps.notOK()) {
+ return Result.err(reps);
+ } else {
+ output = epDF.newData(trans).load(reps.value).asString();
+ synchronized(GET_ENDPOINTS) {
+ epsCache.put(key, output);
+ }
+ }
+ }
+ resp.getOutputStream().println(output);
+ setContentType(resp,epDF.getOutType());
+ return Result.ok();
+ } catch (Exception e) {
+ trans.error().log(e,IN,API_EXAMPLE);
+ return Result.err(Result.ERR_NotImplemented,e.getMessage());
+ } finally {
+ tt.done();
+ }
+ }
+
+ private static final String PUT_MGMT_ENDPOINTS = "Put Mgmt Endpoints";
+ /* (non-Javadoc)
+ * @see org.onap.aaf.auth.locate.facade.GwFacade#putMgmtEndpoints(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ public Result<Void> putMgmtEndpoints(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {
+ TimeTaken tt = trans.start(PUT_MGMT_ENDPOINTS, Env.SUB|Env.ALWAYS);
+ try {
+ MGMT_ENDPOINTS rreq;
+ try {
+ RosettaData<MGMT_ENDPOINTS> data = mepDF.newData().load(req.getInputStream());
+ rreq = data.asObject();
+ } catch(APIException e) {
+ trans.error().log("Invalid Input",IN,PUT_MGMT_ENDPOINTS);
+ return Result.err(Status.ERR_BadData,"Invalid Input");
+
+ }
+ Result<Void> rp = service.putMgmtEndPoints(trans, rreq);
+ switch(rp.status) {
+ case OK:
+ synchronized(GET_ENDPOINTS) {
+ cacheClear = 0L;
+ }
+ setContentType(resp,mepDF.getOutType());
+ return Result.ok();
+ default:
+ return rp;
+ }
+ } catch (Exception e) {
+ trans.error().log(e,IN,PUT_MGMT_ENDPOINTS);
+ return Result.err(e);
+ } finally {
+ tt.done();
+ }
+ }
+
+ private static final String DELETE_MGMT_ENDPOINTS = "Delete Mgmt Endpoints";
+ /* (non-Javadoc)
+ * @see org.onap.aaf.auth.locate.facade.GwFacade#removeMgmtEndpoints(org.onap.aaf.auth.env.test.AuthzTrans, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ @Override
+ public Result<Void> removeMgmtEndpoints(AuthzTrans trans, HttpServletRequest req, HttpServletResponse resp) {
+ TimeTaken tt = trans.start(DELETE_MGMT_ENDPOINTS, Env.SUB|Env.ALWAYS);
+ try {
+ MGMT_ENDPOINTS rreq;
+ try {
+ RosettaData<MGMT_ENDPOINTS> data = mepDF.newData().load(req.getInputStream());
+ rreq = data.asObject();
+ } catch(APIException e) {
+ trans.error().log("Invalid Input",IN,DELETE_MGMT_ENDPOINTS);
+ return Result.err(Status.ERR_BadData,"Invalid Input");
+
+ }
+ Result<Void> rp = service.removeMgmtEndPoints(trans, rreq);
+ switch(rp.status) {
+ case OK:
+ synchronized(GET_ENDPOINTS) {
+ cacheClear = 0L;
+ }
+ setContentType(resp,mepDF.getOutType());
+ return Result.ok();
+ default:
+ return rp;
+ }
+ } catch (Exception e) {
+ trans.error().log(e,IN,DELETE_MGMT_ENDPOINTS);
+ return Result.err(e);
+ } finally {
+ tt.done();
+ }
+ }
+
+} \ No newline at end of file
diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacade_1_0.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacade_1_0.java
new file mode 100644
index 00000000..e2d2c9f6
--- /dev/null
+++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/facade/LocateFacade_1_0.java
@@ -0,0 +1,40 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.auth.locate.facade;
+
+import org.onap.aaf.auth.env.AuthzEnv;
+import org.onap.aaf.auth.locate.service.LocateService;
+import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.env.Data;
+
+import locate.v1_0.Endpoints;
+import locate.v1_0.MgmtEndpoints;
+import locate_local.v1_0.InRequest;
+import locate_local.v1_0.Out;
+import locate_local.v1_0.Error;
+
+public class LocateFacade_1_0 extends LocateFacadeImpl<InRequest,Out,Endpoints,MgmtEndpoints,Error>
+{
+ public LocateFacade_1_0(AuthzEnv env, LocateService<InRequest,Out,Endpoints,MgmtEndpoints,Error> service, Data.TYPE type) throws APIException {
+ super(env, service, type);
+ }
+}
diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/mapper/Mapper.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/mapper/Mapper.java
new file mode 100644
index 00000000..685d096f
--- /dev/null
+++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/mapper/Mapper.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.auth.locate.mapper;
+
+import java.util.List;
+
+import org.onap.aaf.auth.dao.cass.LocateDAO.Data;
+import org.onap.aaf.auth.layer.Result;
+
+import locate.v1_0.MgmtEndpoint;
+
+public interface Mapper<IN,OUT,ENDPOINTS,MGMT_ENDPOINTS,ERROR>
+{
+ public enum API{IN_REQ,OUT,ENDPOINTS,MGMT_ENDPOINTS,ERROR,VOID};
+ public Class<?> getClass(API api);
+ public<A> A newInstance(API api);
+
+ public ERROR errorFromMessage(StringBuilder holder, String msgID, String text, String... detail);
+ public Result<ENDPOINTS> endpoints(Result<List<Data>> resultDB, String version, String other);
+ public Data locateData(MgmtEndpoint me);
+
+}
diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/mapper/Mapper_1_0.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/mapper/Mapper_1_0.java
new file mode 100644
index 00000000..50839b73
--- /dev/null
+++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/mapper/Mapper_1_0.java
@@ -0,0 +1,150 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.auth.locate.mapper;
+
+import java.util.List;
+
+import org.onap.aaf.auth.dao.cass.LocateDAO.Data;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.cadi.util.Vars;
+import org.onap.aaf.misc.env.util.Split;
+
+import locate.v1_0.Endpoint;
+import locate.v1_0.Endpoints;
+import locate.v1_0.MgmtEndpoint;
+import locate.v1_0.MgmtEndpoints;
+import locate_local.v1_0.Error;
+import locate_local.v1_0.InRequest;
+import locate_local.v1_0.Out;
+
+public class Mapper_1_0 implements Mapper<InRequest,Out,Endpoints,MgmtEndpoints,Error> {
+
+ @Override
+ public Class<?> getClass(API api) {
+ switch(api) {
+ case IN_REQ: return InRequest.class;
+ case OUT: return Out.class;
+ case ERROR: return Error.class;
+ case VOID: return Void.class;
+ case ENDPOINTS: return Endpoints.class;
+ case MGMT_ENDPOINTS: return MgmtEndpoints.class;
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <A> A newInstance(API api) {
+ switch(api) {
+ case IN_REQ: return (A) new InRequest();
+ case OUT: return (A) new Out();
+ case ERROR: return (A)new Error();
+ case ENDPOINTS: return (A) new Endpoints();
+ case MGMT_ENDPOINTS: return (A) new MgmtEndpoints();
+ case VOID: return null;
+ }
+ return null;
+ }
+
+ ////////////// Mapping Functions /////////////
+ @Override
+ public locate_local.v1_0.Error errorFromMessage(StringBuilder holder, String msgID, String text,String... var) {
+ Error err = new Error();
+ err.setMessageId(msgID);
+ // AT&T Restful Error Format requires numbers "%" placements
+ err.setText(Vars.convert(holder, text, var));
+ for(String s : var) {
+ err.getVariables().add(s);
+ }
+ return err;
+ }
+
+ /* (non-Javadoc)
+ * @see org.onap.aaf.auth.locate.mapper.Mapper#endpoints(org.onap.aaf.auth.layer.test.Result, java.lang.String, java.lang.String)
+ */
+ @Override
+ public Result<Endpoints> endpoints(Result<List<Data>> resultDB, String version, String other) {
+ if(resultDB.notOK()) {
+ return Result.err(resultDB);
+ }
+ int major=-1, minor=-1, patch=-1, pkg=-1;
+ if(version!=null) {
+ try {
+ String[] v = Split.split('.',version);
+ if(v.length>0) {major = Integer.parseInt(v[0]);}
+ if(v.length>1) {minor = Integer.parseInt(v[1]);}
+ if(v.length>2) {patch = Integer.parseInt(v[2]);}
+ if(v.length>3) {pkg = Integer.parseInt(v[3]);}
+ } catch (NumberFormatException e) {
+ return Result.err(Result.ERR_BadData,"Invalid Version String " + version);
+ }
+ }
+ Endpoints eps = new Endpoints();
+ List<Endpoint> leps = eps.getEndpoint();
+ for(Data d : resultDB.value) {
+ if((major<0 || major==d.major) &&
+ (minor<0 || minor<=d.minor) &&
+ (patch<0 || patch==d.patch) &&
+ (pkg<0 || pkg ==d.pkg)) {
+ Endpoint ep = new Endpoint();
+ ep.setName(d.name);
+ ep.setHostname(d.hostname);
+ ep.setPort(d.port);
+ ep.setMajor(d.major);
+ ep.setMinor(d.minor);
+ ep.setPatch(d.patch);
+ ep.setPkg(d.pkg);
+ ep.setLatitude(d.latitude);
+ ep.setLongitude(d.longitude);
+ ep.setProtocol(d.protocol);
+ for(String s : d.subprotocol(false)) {
+ ep.getSubprotocol().add(s);
+ }
+ leps.add(ep);
+ }
+ }
+ return Result.ok(eps);
+ }
+
+ /* (non-Javadoc)
+ * @see org.onap.aaf.auth.locate.mapper.Mapper#locateData(locate.v1_0.MgmtEndpoint)
+ */
+ @Override
+ public Data locateData(MgmtEndpoint me) {
+ Data data = new Data();
+ data.name = me.getName();
+ data.port = me.getPort();
+ data.hostname = me.getHostname();
+ data.major = me.getMajor();
+ data.minor = me.getMinor();
+ data.patch = me.getPatch();
+ data.pkg = me.getPkg();
+ data.latitude = me.getLatitude();
+ data.longitude = me.getLongitude();
+ data.protocol = me.getProtocol();
+ for(String s : me.getSubprotocol()) {
+ data.subprotocol(true).add(s);
+ }
+ return data;
+ }
+
+} \ No newline at end of file
diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateService.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateService.java
new file mode 100644
index 00000000..d2a37348
--- /dev/null
+++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateService.java
@@ -0,0 +1,33 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.auth.locate.service;
+
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.auth.locate.mapper.Mapper;
+
+public interface LocateService<IN,OUT,ENDPOINTS,MGMT_ENDPOINTS,ERROR> {
+ public Mapper<IN,OUT,ENDPOINTS,MGMT_ENDPOINTS,ERROR> mapper();
+ public Result<ENDPOINTS> getEndPoints(AuthzTrans trans, String service, String version, String other);
+ public Result<Void> putMgmtEndPoints(AuthzTrans trans, MGMT_ENDPOINTS meps);
+ public Result<Void> removeMgmtEndPoints(AuthzTrans trans, MGMT_ENDPOINTS meps);
+}
diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateServiceImpl.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateServiceImpl.java
new file mode 100644
index 00000000..d1a03cdc
--- /dev/null
+++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/service/LocateServiceImpl.java
@@ -0,0 +1,122 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.auth.locate.service;
+
+import java.util.UUID;
+
+import org.onap.aaf.auth.dao.cass.LocateDAO;
+import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.layer.Result;
+import org.onap.aaf.auth.locate.mapper.Mapper;
+import org.onap.aaf.auth.locate.validation.LocateValidator;
+import org.onap.aaf.cadi.aaf.AAFPermission;
+import org.onap.aaf.misc.env.APIException;
+
+import locate.v1_0.Endpoints;
+import locate.v1_0.MgmtEndpoint;
+import locate.v1_0.MgmtEndpoints;
+
+public class LocateServiceImpl<IN,OUT,ERROR>
+ implements LocateService<IN,OUT,Endpoints,MgmtEndpoints,ERROR> {
+ private Mapper<IN,OUT,Endpoints,MgmtEndpoints,ERROR> mapper;
+ private LocateDAO locateDAO;
+ private boolean permToRegister;
+
+ public LocateServiceImpl(AuthzTrans trans, LocateDAO locateDAO, Mapper<IN,OUT,Endpoints,MgmtEndpoints,ERROR> mapper) throws APIException {
+ this.mapper = mapper;
+ this.locateDAO = locateDAO;
+ permToRegister = false; //TODO Setup a Configuration for this
+ }
+
+ public Mapper<IN,OUT,Endpoints,MgmtEndpoints,ERROR> mapper() {return mapper;}
+
+ @Override
+ public Result<Endpoints> getEndPoints(AuthzTrans trans, String service, String version, String other) {
+ return mapper.endpoints(locateDAO.readByName(trans, service), version, other);
+ }
+
+ /* (non-Javadoc)
+ * @see org.onap.aaf.auth.locate.service.GwService#putMgmtEndPoints(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object)
+ */
+ @Override
+ public Result<Void> putMgmtEndPoints(AuthzTrans trans, MgmtEndpoints meps) {
+ LocateValidator v = new LocateValidator().mgmt_endpoints(meps, false);
+ if(v.err()) {
+ return Result.err(Result.ERR_BadData,v.errs());
+ }
+ int count = 0;
+ for(MgmtEndpoint me : meps.getMgmtEndpoint()) {
+ if(permToRegister) {
+ int dot = me.getName().lastIndexOf('.'); // Note: Validator checks for NS for getName()
+ AAFPermission p = new AAFPermission(me.getName().substring(0,dot)+".locator",me.getName(),"write");
+ if(trans.fish(p)) {
+ LocateDAO.Data data = mapper.locateData(me);
+ locateDAO.update(trans, data, true);
+ ++count;
+ } else {
+ return Result.err(Result.ERR_Denied,"May not register service (needs " + p.getKey() + ')');
+ }
+ } else { //TODO if(MechID is part of Namespace) {
+ LocateDAO.Data data = mapper.locateData(me);
+ locateDAO.update(trans, data, true);
+ ++count;
+ }
+ }
+ if(count>0) {
+ return Result.ok();
+ } else {
+ return Result.err(Result.ERR_NotFound, "No endpoints found");
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.onap.aaf.auth.locate.service.GwService#removeMgmtEndPoints(org.onap.aaf.auth.env.test.AuthzTrans, java.lang.Object)
+ */
+ @Override
+ public Result<Void> removeMgmtEndPoints(AuthzTrans trans, MgmtEndpoints meps) {
+ LocateValidator v = new LocateValidator().mgmt_endpoint_key(meps);
+ if(v.err()) {
+ return Result.err(Result.ERR_BadData,v.errs());
+ }
+ int count = 0;
+ for(MgmtEndpoint me : meps.getMgmtEndpoint()) {
+ int dot = me.getName().lastIndexOf('.'); // Note: Validator checks for NS for getName()
+ AAFPermission p = new AAFPermission(me.getName().substring(0,dot)+".locator",me.getHostname(),"write");
+ if(trans.fish(p)) {
+ LocateDAO.Data data = mapper.locateData(me);
+ data.port_key = UUID.randomUUID();
+ locateDAO.delete(trans, data, false);
+ ++count;
+ } else {
+ return Result.err(Result.ERR_Denied,"May not register service (needs " + p.getKey() + ')');
+ }
+ }
+ if(count>0) {
+ return Result.ok();
+ } else {
+ return Result.err(Result.ERR_NotFound, "No endpoints found");
+ }
+ }
+
+
+//////////////// APIs ///////////////////
+};
diff --git a/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/validation/LocateValidator.java b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/validation/LocateValidator.java
new file mode 100644
index 00000000..89157826
--- /dev/null
+++ b/auth/auth-locate/src/main/java/org/onap/aaf/auth/locate/validation/LocateValidator.java
@@ -0,0 +1,141 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.auth.locate.validation;
+
+import org.onap.aaf.auth.validation.Validator;
+
+import locate.v1_0.Endpoint;
+import locate.v1_0.Endpoints;
+import locate.v1_0.MgmtEndpoint;
+import locate.v1_0.MgmtEndpoint.SpecialPorts;
+import locate.v1_0.MgmtEndpoints;
+
+/**
+ * Validator
+ * Consistently apply content rules for content (incoming)
+ *
+ * Note: We restrict content for usability in URLs (because RESTful service), and avoid
+ * issues with Regular Expressions, and other enabling technologies.
+ * @author Jonathan
+ *
+ */
+public class LocateValidator extends Validator {
+ private LocateValidator endpoint_key(Endpoint e) {
+ if(e==null) {
+ msg("Endpoint Data is null.");
+ } else {
+ nullOrBlank("Endpoint Name", e.getName());
+ if(e.getName()!=null) {
+ int idx = e.getName().indexOf('.');
+ if(idx<=0) {
+ msg("Endpoint Name must prefixed by Namespace");
+ }
+ }
+ nullOrBlank("Endpoint Hostname", e.getHostname());
+ intRange("Endpoint Port",e.getPort(),0,1000000);
+ }
+ return this;
+ }
+
+
+ public LocateValidator endpoint(Endpoint e) {
+ endpoint_key(e);
+ if(e!=null) {
+ intRange("Endpoint Major Version",e.getMajor(),0,2000);
+ intRange("Endpoint Minor Version",e.getMinor(),0,2000);
+ intRange("Endpoint Patch Version",e.getPatch(),0,2000);
+ intRange("Endpoint Pkg Version",e.getPkg(),0,2000);
+ floatRange("Endpoint Latitude",e.getLatitude(),-90f,90f);
+ floatRange("Endpoint Longitude",e.getLongitude(),-180f,180f);
+ nullOrBlank("Endpoint Protocol", e.getProtocol());
+ for(String s : e.getSubprotocol()) {
+ nullOrBlank("Endpoint Subprotocol", s);
+ }
+ }
+ return this;
+ }
+
+ public LocateValidator endpoints(Endpoints e, boolean emptyNotOK) {
+ if(e==null) {
+ msg("Endpoints Data is null.");
+ } else {
+ if(emptyNotOK && e.getEndpoint().size()==0) {
+ msg("Endpoints contains no endpoints");
+ } else {
+ for(Endpoint ep : e.getEndpoint()) {
+ endpoint(ep);
+ }
+ }
+ }
+ return this;
+ }
+
+ public LocateValidator mgmt_endpoint_key(MgmtEndpoints meps) {
+ if(meps==null) {
+ msg("MgmtEndpoints Data is null.");
+ } else {
+ for(MgmtEndpoint ep : meps.getMgmtEndpoint()) {
+ endpoint_key(ep);
+ }
+ }
+ return this;
+ }
+
+ public LocateValidator mgmt_endpoints(MgmtEndpoints me, boolean emptyOK) {
+ if(me==null) {
+ msg("MgmtEndpoints Data is null.");
+ } else {
+ if(!emptyOK && me.getMgmtEndpoint().size()==0) {
+ msg("MgmtEndpoints contains no data");
+ } else {
+ for(MgmtEndpoint ep : me.getMgmtEndpoint()) {
+ mgmt_endpoint(ep);
+ }
+ }
+ }
+ return this;
+ }
+
+ private LocateValidator mgmt_endpoint(MgmtEndpoint ep) {
+ endpoint(ep);
+ for(SpecialPorts sp : ep.getSpecialPorts()) {
+ specialPorts(sp);
+ }
+ return this;
+ }
+
+ private LocateValidator specialPorts(SpecialPorts sp) {
+ if(sp==null) {
+ msg("Special Ports is null.");
+ } else {
+ nullOrBlank("Special Port Name",sp.getName());
+ nullOrBlank("Special Port Protocol",sp.getProtocol());
+ intRange("Special Port",sp.getPort(),0,1000000);
+
+ for(String s : sp.getProtocolVersions()) {
+ nullOrBlank("Special Port Protocol Version", s);
+ }
+ }
+ return this;
+ }
+
+}
diff --git a/auth/auth-locate/src/main/xsd/locate_1_0.xsd b/auth/auth-locate/src/main/xsd/locate_1_0.xsd
new file mode 100644
index 00000000..ea7b3cce
--- /dev/null
+++ b/auth/auth-locate/src/main/xsd/locate_1_0.xsd
@@ -0,0 +1,122 @@
+<!--
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ * ===========================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+-->
+<xs:schema
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:locate_local="urn:locate_local:v1_0"
+ targetNamespace="urn:locate_local:v1_0"
+ elementFormDefault="qualified">
+
+
+<!--
+ Requests
+ -->
+ <xs:complexType name="Request">
+ <xs:sequence>
+ </xs:sequence>
+ </xs:complexType>
+
+<!--
+ In
+-->
+ <xs:element name="inRequest">
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:extension base="locate_local:Request">
+ <xs:sequence>
+ <xs:element name="name" type="xs:string"/>
+ <xs:element name="action" type="xs:string"/>
+ </xs:sequence>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+
+
+<!--
+ Out
+-->
+ <xs:element name="out">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="name" type="xs:string"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+<!-- **************** STANDARD ELEMENTS ******************* -->
+<!--
+ Errors
+ Note: This Error Structure has been made to conform to the AT&T TSS Policies
+ -->
+ <xs:element name="error">
+ <xs:complexType>
+ <xs:sequence>
+ <!--
+ Unique message identifier of the format ‘ABCnnnn’ where ‘ABC’ is
+ either ‘SVC’ for Service Exceptions or ‘POL’ for Policy Exception.
+ Exception numbers may be in the range of 0001 to 9999 where :
+ * 0001 to 0199 are reserved for common exception messages
+ * 0200 to 0999 are reserved for Parlay Web Services specification use
+ * 1000-9999 are available for exceptions
+ -->
+ <xs:element name="messageId" type="xs:string" minOccurs="1" maxOccurs="1"/>
+
+ <!--
+ Message text, with replacement
+ variables marked with %n, where n is
+ an index into the list of <variables>
+ elements, starting at 1
+ -->
+ <xs:element name="text" type="xs:string" minOccurs="1" maxOccurs="1"/>
+
+ <!--
+ List of zero or more strings that
+ represent the contents of the variables
+ used by the message text. -->
+ <xs:element name="variables" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+<!--
+ API
+-->
+ <xs:element name="api">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="route" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="meth" type="xs:string" minOccurs="1" maxOccurs="1"/>
+ <xs:element name="path" type="xs:string" minOccurs="1" maxOccurs="1"/>
+ <xs:element name="param" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="desc" type="xs:string" minOccurs="1" maxOccurs="1"/>
+ <xs:element name="comments" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="contentType" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="expected" type="xs:int" minOccurs="1" maxOccurs="1"/>
+ <xs:element name="explicitErr" type="xs:int" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+</xs:schema> \ No newline at end of file