Skip to content

Commit

Permalink
httpd: Refactor handler instantiation
Browse files Browse the repository at this point in the history
AliasEntry was tightly coupled to HttpServiceCell (apparent in that a admin
shell Args instance was passed to the AliasEntry factory method, and in that
several getters of HttpServiceCell were only used by the AliasEntry factory).

This patch moves the alias and handler creation into HttpServiceCell, thus
reducing coupling of AliasEntry.

The patch also simplifies the AliasType enum.

Target: trunk
Require-notes: no
Require-book: no
Acked-by: Albert Rossi <arossi@fnal.gov>
Patch: https://rb.dcache.org/r/7423/
  • Loading branch information
gbehrmann committed Oct 31, 2014
1 parent a0594fd commit 3d17f6f
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 220 deletions.
@@ -1,14 +1,20 @@
package org.dcache.services.httpd;

import org.eclipse.jetty.plus.jndi.EnvEntry;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.net.URL;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Properties;

import dmg.cells.nucleus.CellCommandListener;
import dmg.cells.nucleus.CellEndpoint;
Expand All @@ -20,10 +26,17 @@
import dmg.cells.nucleus.EnvironmentAware;
import dmg.util.CommandInterpreter;

import org.dcache.services.httpd.handlers.BadConfigHandler;
import org.dcache.services.httpd.handlers.ContextHandler;
import org.dcache.services.httpd.handlers.HandlerDelegator;
import org.dcache.services.httpd.handlers.PathHandler;
import org.dcache.services.httpd.handlers.RedirectHandler;
import org.dcache.services.httpd.handlers.ResponseEngineHandler;
import org.dcache.services.httpd.util.AliasEntry;
import org.dcache.util.Args;

import static org.dcache.services.httpd.util.AliasEntry.AliasType;

public class HttpServiceCell extends CommandInterpreter
implements CellMessageReceiver,
CellMessageSender,
Expand All @@ -34,6 +47,18 @@ public class HttpServiceCell extends CommandInterpreter
{
private static final Logger logger = LoggerFactory.getLogger(HttpServiceCell.class);

private static final String[] configClasses = {
"org.eclipse.jetty.webapp.WebInfConfiguration",
"org.eclipse.jetty.webapp.WebXmlConfiguration",
"org.eclipse.jetty.webapp.MetaInfConfiguration",
"org.eclipse.jetty.webapp.FragmentConfiguration",
"org.eclipse.jetty.plus.webapp.EnvConfiguration",
"org.eclipse.jetty.plus.webapp.PlusConfiguration",
"org.eclipse.jetty.webapp.JettyWebXmlConfiguration" };

public static final String CELL_ENDPOINT = "serviceCellEndpoint";
public static final String JNDI_ARGS = "jndiArgs";

/**
* Where the war should be unpacked
*/
Expand Down Expand Up @@ -66,7 +91,6 @@ public class HttpServiceCell extends CommandInterpreter
}

public static final String hh_set_alias = "<aliasName> directory|class|context <specification>";

public static final String fh_set_alias = "set alias <alias> <type> [<typeSpecific> <...>]\n"
+ " <type> <specific> \n"
+ " directory <fullDirectoryPath>\n"
Expand All @@ -78,28 +102,139 @@ public class HttpServiceCell extends CommandInterpreter
+ " redirect <forward-to-context>\n"
+ " predefined alias : <home> = default for http://host:port/ \n"
+ " <default> = default for any type or error \n";

public String ac_set_alias_$_3_16(Args args) throws Exception {
logger.debug("ac_set_alias_$_3_16 {}", args.toString());
AliasEntry entry = AliasEntry.createEntry(args, this);
logger.debug("putting {}, {}", entry.getName(), entry);
public String ac_set_alias_$_3_16(Args args) throws Exception
{
String alias = args.argv(0);
String type = args.argv(1);
args.shift(2);
AliasEntry entry = createEntry(alias, type, args);
logger.debug("Creating alias {}: {}", entry.getName(), entry);
delegator.addAlias(entry.getName(), entry);
return entry.getStatusMessage();
}

public static final String hh_unset_alias = "<aliasName>";

public String ac_unset_alias_$_1(Args args) {
public String ac_unset_alias_$_1(Args args)
{
delegator.removeAlias(args.argv(0));
return "Done";
}

public String getDefaultWebappsXml() {
return defaultWebappsXml;
private AliasEntry createEntry(String alias, String type, Args args) throws Exception
{
String specific = args.argv(0);

AliasType aliasType = AliasType.fromType(type);
AliasEntry entry;
Handler handler;
String failure = null;

switch (aliasType) {
case FILE:
case DIR:
File dir = new File(specific);
if ((!dir.isDirectory()) && (!dir.isFile())) {
throw new FileNotFoundException(specific);
}
handler = new PathHandler(dir);
entry = new AliasEntry(alias, aliasType, handler, specific);
entry.setStatusMessage(alias + " -> " + aliasType.getType() + "(" + specific + ")");
break;
case CONTEXT:
handler = new ContextHandler(specific, domainContext);
entry = new AliasEntry(alias, aliasType, handler, specific);
entry.setOnError(args.getOpt("onError"));
entry.setOverwrite(args.getOpt("overwrite"));
entry.setStatusMessage(alias + " -> " + aliasType.getType() + "(" + specific + ")");
break;
case REDIRECT:
handler = new RedirectHandler(alias, specific);
entry = new AliasEntry(alias, aliasType, handler, specific);
entry.setStatusMessage(alias + " -> " + aliasType.getType() + "(" + specific + ")");
break;
case ENGINE:
args.shift();
int argcount = args.argc();
String[] handlerArgs = new String[argcount];
StringBuilder sb = new StringBuilder();
sb.append("class=").append(specific);

for (int i = 0; i < argcount; i++) {
handlerArgs[i] = args.argv(i);
sb.append(";").append(handlerArgs[i]);
}

ResponseEngineHandler rhandler
= new ResponseEngineHandler(specific, handlerArgs);

try {
rhandler.initialize(this);
handler = rhandler;
} catch (Exception e) {
handler = new BadConfigHandler();
aliasType = AliasType.BADCONFIG;
failure = "failed to load class " + specific;
sb.append(" FAILED TO LOAD CLASS");
}

entry = new AliasEntry(alias, aliasType, handler, sb.toString());
entry.setIntFailureMsg(failure);
entry.setStatusMessage(alias + " -> " + aliasType.getType() + "(" + entry.getSpecificString() + ")");
break;
case WEBAPP:
handler = createWebAppContext(alias, specific);
entry = new AliasEntry(alias, aliasType, handler, args.toString());
entry.setStatusMessage(alias + " -> " + aliasType.getType() + "(" + args + ")");
break;
case BADCONFIG:
handler = new BadConfigHandler();
entry = new AliasEntry(alias, aliasType, handler, specific);
entry.setStatusMessage(alias + " -> " + aliasType.getType() + "(" + specific + ")");
break;
default:
throw new RuntimeException("Unreachable statement (" + aliasType + ")");
}

if (handler instanceof BadConfigHandler) {
((BadConfigHandler) handler).setFailureMessage(entry.getIntFailureMsg());
}
return entry;
}

public Map<String, Object> getDomainContext() {
return domainContext;
private Handler createWebAppContext(String alias, String webappsPath)
throws Exception
{
String context = "/" + alias;
Map<String, Object> env = getEnvironment();

File war = new File(webappsPath, context + ".war");
File tmpDir = new File(getTmpUnpackDir(), alias);

WebAppContext webappContext = new WebAppContext();
webappContext.setDefaultsDescriptor(defaultWebappsXml);
webappContext.setContextPath(context);
webappContext.setWar(war.getAbsolutePath());
webappContext.setExtractWAR(true);
webappContext.setTempDirectory(tmpDir);
webappContext.setConfigurationClasses(configClasses);

/*
* export to JNDI (constructor binds the entry into JNDI); all resources
* and env entries are scoped to the webapp context
*/
new EnvEntry(webappContext, CELL_ENDPOINT, endpoint, true);

Properties properties = new Properties();
for (String key : env.keySet()) {
properties.setProperty(key, String.valueOf(env.get(key)));
}

new EnvEntry(webappContext, JNDI_ARGS, properties, true);

webappContext.setServer(server);
webappContext.start();

return webappContext;
}

public CellEndpoint getEndpoint() {
Expand Down
Expand Up @@ -117,8 +117,7 @@ public void handle(String target, Request baseRequest,
* The exclusion of POST used to be absolute; we allow it now only
* on webapps.
*/
if (!request.getMethod().equals("GET")
&& !entry.getType().equals(AliasEntry.TYPE_WEBAPP)) {
if (!request.getMethod().equals("GET") && entry.getType() != AliasEntry.AliasType.WEBAPP) {
throw new HttpException(HttpServletResponse.SC_NOT_IMPLEMENTED,
"Method not implemented: " + request.getMethod());
}
Expand Down Expand Up @@ -174,9 +173,9 @@ public void handle(String target, Request baseRequest,
logger.info("Finished");
}

public void removeAlias(String name)
public AliasEntry removeAlias(String name)
{
aliases.remove(name);
return aliases.remove(name);
}

public void addAlias(String name, AliasEntry entry)
Expand Down

0 comments on commit 3d17f6f

Please sign in to comment.