diff options
Diffstat (limited to 'policy-endpoints/src/main/java/org/openecomp/policy/drools/http/server/internal/JettyServletServer.java')
-rw-r--r-- | policy-endpoints/src/main/java/org/openecomp/policy/drools/http/server/internal/JettyServletServer.java | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/policy-endpoints/src/main/java/org/openecomp/policy/drools/http/server/internal/JettyServletServer.java b/policy-endpoints/src/main/java/org/openecomp/policy/drools/http/server/internal/JettyServletServer.java new file mode 100644 index 00000000..74360e80 --- /dev/null +++ b/policy-endpoints/src/main/java/org/openecomp/policy/drools/http/server/internal/JettyServletServer.java @@ -0,0 +1,353 @@ +/*- + * ============LICENSE_START======================================================= + * policy-endpoints + * ================================================================================ + * 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========================================================= + */ +package org.openecomp.policy.drools.http.server.internal; + +import org.eclipse.jetty.security.ConstraintMapping; +import org.eclipse.jetty.security.ConstraintSecurityHandler; +import org.eclipse.jetty.security.HashLoginService; +import org.eclipse.jetty.security.authentication.BasicAuthenticator; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.util.security.Constraint; +import org.eclipse.jetty.util.security.Credential; + +import org.openecomp.policy.common.logging.eelf.MessageCodes; +import org.openecomp.policy.common.logging.flexlogger.FlexLogger; +import org.openecomp.policy.common.logging.flexlogger.Logger; +import org.openecomp.policy.drools.http.server.HttpServletServer; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +/** + * Http Server implementation using Embedded Jetty + */ +public abstract class JettyServletServer implements HttpServletServer, Runnable { + + private static Logger logger = FlexLogger.getLogger(JettyServletServer.class); + + protected final String name; + + protected final String host; + protected final int port; + + protected String user; + protected String password; + + protected final String contextPath; + + protected final Server jettyServer; + protected final ServletContextHandler context; + protected final ServerConnector connector; + + protected volatile Thread jettyThread; + + protected Object startCondition = new Object(); + + public JettyServletServer(String name, String host, int port, String contextPath) + throws IllegalArgumentException { + + if (name == null || name.isEmpty()) + name = "http-" + port; + + if (port <= 0 && port >= 65535) + throw new IllegalArgumentException("Invalid Port provided: " + port); + + if (host == null || host.isEmpty()) + host = "localhost"; + + if (contextPath == null || contextPath.isEmpty()) + contextPath = "/"; + + this.name = name; + + this.host = host; + this.port = port; + + this.contextPath = contextPath; + + this.context = new ServletContextHandler(ServletContextHandler.SESSIONS); + this.context.setContextPath(contextPath); + + this.jettyServer = new Server(); + + this.connector = new ServerConnector(this.jettyServer); + this.connector.setName(name); + this.connector.setReuseAddress(true); + this.connector.setPort(port); + this.connector.setHost(host); + + this.jettyServer.addConnector(this.connector); + this.jettyServer.setHandler(context); + } + + /** + * {@inheritDoc} + */ + @Override + public void setBasicAuthentication(String user, String password, String servletPath) { + if (user == null || user.isEmpty() || password == null || password.isEmpty()) + throw new IllegalArgumentException("Missing user and/or password"); + + if (servletPath == null || servletPath.isEmpty()) + servletPath = "/*"; + + HashLoginService hashLoginService = new HashLoginService(); + hashLoginService.putUser(user, + Credential.getCredential(password), + new String[] {"user"}); + hashLoginService.setName(this.connector.getName() + "-login-service"); + + Constraint constraint = new Constraint(); + constraint.setName(Constraint.__BASIC_AUTH); + constraint.setRoles(new String[]{"user"}); + constraint.setAuthenticate(true); + + ConstraintMapping constraintMapping = new ConstraintMapping(); + constraintMapping.setConstraint(constraint); + constraintMapping.setPathSpec(servletPath); + + ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler(); + securityHandler.setAuthenticator(new BasicAuthenticator()); + securityHandler.setRealmName(this.connector.getName() + "-realm"); + securityHandler.addConstraintMapping(constraintMapping); + securityHandler.setLoginService(hashLoginService); + + this.context.setSecurityHandler(securityHandler); + + this.user = user; + this.password = password; + } + + /** + * Jetty Server Execution + */ + @Override + public void run() { + try { + if (logger.isInfoEnabled()) + logger.info(this + " STARTING " + this.jettyServer.dump()); + + this.jettyServer.start(); + + synchronized(this.startCondition) { + this.startCondition.notifyAll(); + } + + this.jettyServer.join(); + } catch (Exception e) { + logger.warn(MessageCodes.EXCEPTION_ERROR, e, + "Error found while running management server", this.toString()); + } + } + + @Override + public boolean waitedStart(long maxWaitTime) throws IllegalArgumentException { + + if (maxWaitTime < 0) + throw new IllegalArgumentException("max-wait-time cannot be negative"); + + long pendingWaitTime = maxWaitTime; + + if (!this.start()) + return false; + + synchronized (this.startCondition) { + + while (!this.jettyServer.isRunning()) { + try { + long startTs = System.currentTimeMillis(); + + this.startCondition.wait(pendingWaitTime); + + if (maxWaitTime == 0) + /* spurious notification */ + continue; + + long endTs = System.currentTimeMillis(); + pendingWaitTime = pendingWaitTime - (endTs - startTs); + + if (logger.isInfoEnabled()) + logger.info(this + "Pending time is " + pendingWaitTime + + " ms."); + + if (pendingWaitTime <= 0) + return false; + + } catch (InterruptedException e) { + logger.warn("waited-start has been interrupted"); + return false; + } + } + + return (this.jettyServer.isRunning()); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean start() throws IllegalStateException { + if (logger.isDebugEnabled()) + logger.debug(this + "START"); + + synchronized(this) { + if (jettyThread == null || + !this.jettyThread.isAlive()) { + + this.jettyThread = new Thread(this); + this.jettyThread.setName(this.name + "-" + this.port); + this.jettyThread.start(); + } + } + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean stop() throws IllegalStateException { + logger.info(this + "STOP"); + + synchronized(this) { + if (jettyThread == null) { + return true; + } + + if (!jettyThread.isAlive()) { + this.jettyThread = null; + } + + try { + this.connector.stop(); + } catch (Exception e) { + logger.error(MessageCodes.EXCEPTION_ERROR, e, + "Error while stopping management server", this.toString()); + e.printStackTrace(); + } + + try { + this.jettyServer.stop(); + } catch (Exception e) { + logger.error(MessageCodes.EXCEPTION_ERROR, e, + "Error while stopping management server", this.toString()); + return false; + } + + Thread.yield(); + } + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public void shutdown() throws IllegalStateException { + logger.info(this + "SHUTDOWN"); + + this.stop(); + + if (this.jettyThread == null) + return; + + Thread jettyThreadCopy = this.jettyThread; + + if (jettyThreadCopy.isAlive()) { + try { + jettyThreadCopy.join(1000L); + } catch (InterruptedException e) { + logger.warn(MessageCodes.EXCEPTION_ERROR, e, + "Error while shutting down management server", this.toString()); + } + if (!jettyThreadCopy.isInterrupted()) { + try { + jettyThreadCopy.interrupt(); + } catch(Exception e) { + // do nothing + logger.warn("exception while shutting down (OK)"); + } + } + } + + this.jettyServer.destroy(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isAlive() { + if (this.jettyThread != null) + return this.jettyThread.isAlive(); + + return false; + } + + @Override + public int getPort() { + return this.port; + } + + /** + * @return the name + */ + public String getName() { + return name; + } + + /** + * @return the host + */ + public String getHost() { + return host; + } + + /** + * @return the user + */ + public String getUser() { + return user; + } + + /** + * @return the password + */ + @JsonIgnore + public String getPassword() { + return password; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("JettyServer [name=").append(name).append(", host=").append(host).append(", port=").append(port) + .append(", user=").append(user).append(", password=").append((password != null)).append(", contextPath=") + .append(contextPath).append(", jettyServer=").append(jettyServer).append(", context=").append(this.context) + .append(", connector=").append(connector).append(", jettyThread=").append(jettyThread) + .append("]"); + return builder.toString(); + } + +} |