001: /**
002: *
003: * Licensed to the Apache Software Foundation (ASF) under one or more
004: * contributor license agreements. See the NOTICE file distributed with
005: * this work for additional information regarding copyright ownership.
006: * The ASF licenses this file to You under the Apache License, Version 2.0
007: * (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */package org.apache.openejb.tomcat.catalina;
018:
019: import org.apache.catalina.Container;
020: import org.apache.catalina.Context;
021: import org.apache.catalina.Engine;
022: import org.apache.catalina.Host;
023: import org.apache.catalina.Lifecycle;
024: import org.apache.catalina.LifecycleEvent;
025: import org.apache.catalina.LifecycleListener;
026: import org.apache.catalina.ServerFactory;
027: import org.apache.catalina.Service;
028: import org.apache.catalina.Wrapper;
029: import org.apache.catalina.authenticator.BasicAuthenticator;
030: import org.apache.catalina.authenticator.DigestAuthenticator;
031: import org.apache.catalina.authenticator.NonLoginAuthenticator;
032: import org.apache.catalina.authenticator.SSLAuthenticator;
033: import org.apache.catalina.connector.Connector;
034: import org.apache.catalina.core.StandardContext;
035: import org.apache.catalina.core.StandardServer;
036: import org.apache.catalina.deploy.LoginConfig;
037: import org.apache.catalina.deploy.SecurityCollection;
038: import org.apache.catalina.deploy.SecurityConstraint;
039: import org.apache.openejb.server.httpd.HttpListener;
040: import org.apache.openejb.server.webservices.WsRegistry;
041: import org.apache.openejb.server.webservices.WsServlet;
042: import static org.apache.openejb.tomcat.catalina.TomcatWebAppBuilder.IGNORE_CONTEXT;
043:
044: import java.net.URI;
045: import java.util.ArrayList;
046: import java.util.Arrays;
047: import java.util.List;
048: import java.util.Map;
049: import java.util.TreeMap;
050:
051: public class TomcatWsRegistry implements WsRegistry {
052: private final Map<String, StandardContext> webserviceContexts = new TreeMap<String, StandardContext>();
053: private Engine engine;
054: private List<Connector> connectors;
055:
056: public TomcatWsRegistry() {
057: StandardServer standardServer = (StandardServer) ServerFactory
058: .getServer();
059: for (Service service : standardServer.findServices()) {
060: if (service.getContainer() instanceof Engine) {
061: connectors = Arrays.asList(service.findConnectors());
062: engine = (Engine) service.getContainer();
063: break;
064: }
065: }
066: }
067:
068: public List<String> setWsContainer(String virtualHost,
069: String contextRoot, String servletName,
070: HttpListener wsContainer) throws Exception {
071: if (virtualHost == null)
072: virtualHost = engine.getDefaultHost();
073:
074: Container host = engine.findChild(virtualHost);
075: if (host == null) {
076: throw new IllegalArgumentException(
077: "Invalid virtual host '"
078: + virtualHost
079: + "'. Do you have a matchiing Host entry in the server.xml?");
080: }
081:
082: Context context = (Context) host.findChild("/" + contextRoot);
083: if (context == null) {
084: throw new IllegalArgumentException(
085: "Could not find web application context "
086: + contextRoot + " in host "
087: + host.getName());
088: }
089:
090: Wrapper wrapper = (Wrapper) context.findChild(servletName);
091: if (wrapper == null) {
092: throw new IllegalArgumentException(
093: "Could not find servlet " + contextRoot
094: + " in web application context "
095: + context.getName());
096: }
097:
098: setWsContainer(context, wrapper, wsContainer);
099:
100: // add service locations
101: List<String> addresses = new ArrayList<String>();
102: for (Connector connector : connectors) {
103: for (String mapping : wrapper.findMappings()) {
104: URI address = new URI(connector.getScheme(), null, host
105: .getName(), connector.getPort(), "/"
106: + contextRoot + mapping, null, null);
107: addresses.add(address.toString());
108: }
109: }
110: return addresses;
111: }
112:
113: public void clearWsContainer(String virtualHost,
114: String contextRoot, String servletName) {
115: if (virtualHost == null)
116: virtualHost = engine.getDefaultHost();
117:
118: Container host = engine.findChild(virtualHost);
119: if (host == null) {
120: throw new IllegalArgumentException(
121: "Invalid virtual host '"
122: + virtualHost
123: + "'. Do you have a matchiing Host entry in the server.xml?");
124: }
125:
126: Context context = (Context) host.findChild("/" + contextRoot);
127: if (context == null) {
128: throw new IllegalArgumentException(
129: "Could not find web application context "
130: + contextRoot + " in host "
131: + host.getName());
132: }
133:
134: Wrapper wrapper = (Wrapper) context.findChild(servletName);
135: if (wrapper == null) {
136: throw new IllegalArgumentException(
137: "Could not find servlet " + contextRoot
138: + " in web application context "
139: + context.getName());
140: }
141:
142: // clear the webservice ref in the servlet context
143: String webServicecontainerId = wrapper
144: .findInitParameter(WsServlet.WEBSERVICE_CONTAINER);
145: if (webServicecontainerId != null) {
146: context.getServletContext().removeAttribute(
147: webServicecontainerId);
148: wrapper.removeInitParameter(WsServlet.WEBSERVICE_CONTAINER);
149: }
150: }
151:
152: public List<String> addWsContainer(String path,
153: HttpListener httpListener, String virtualHost,
154: String realmName, String transportGuarantee,
155: String authMethod, ClassLoader classLoader)
156: throws Exception {
157: if (path == null)
158: throw new NullPointerException("contextRoot is null");
159: if (httpListener == null)
160: throw new NullPointerException("httpListener is null");
161:
162: // assure context root with a leading slash
163: if (!path.startsWith("/"))
164: path = "/" + path;
165:
166: // find the existing host (we do not auto-create hosts)
167: if (virtualHost == null)
168: virtualHost = engine.getDefaultHost();
169: Container host = engine.findChild(virtualHost);
170: if (host == null) {
171: throw new IllegalArgumentException(
172: "Invalid virtual host '"
173: + virtualHost
174: + "'. Do you have a matchiing Host entry in the server.xml?");
175: }
176:
177: // build the context
178: StandardContext context = new StandardContext();
179: context.setPath(path);
180: context.setDocBase("");
181: context.setParentClassLoader(classLoader);
182: context.setDelegate(true);
183:
184: // Tomcat has a stupid rule where a life cycle listener must set
185: // configured true, or it will treat it as a failed deployment
186: context.addLifecycleListener(new LifecycleListener() {
187: public void lifecycleEvent(LifecycleEvent event) {
188: if (event.getType().equals(Lifecycle.START_EVENT)) {
189: Context context = (Context) event.getLifecycle();
190: context.setConfigured(true);
191: }
192: }
193: });
194:
195: // Configure security
196: if (authMethod != null) {
197: authMethod = authMethod.toUpperCase();
198: }
199: if (transportGuarantee != null) {
200: transportGuarantee = transportGuarantee.toUpperCase();
201: }
202: if (authMethod == null || "NONE".equals(authMethod)) {
203: // ignore none for now as the NonLoginAuthenticator seems to be completely hosed
204: } else if ("BASIC".equals(authMethod)
205: || "DIGEST".equals(authMethod)
206: || "CLIENT-CERT".equals(authMethod)) {
207:
208: //Setup a login configuration
209: LoginConfig loginConfig = new LoginConfig();
210: loginConfig.setAuthMethod(authMethod);
211: loginConfig.setRealmName(realmName);
212: context.setLoginConfig(loginConfig);
213:
214: //Setup a default Security Constraint
215: SecurityCollection collection = new SecurityCollection();
216: collection.addMethod("GET");
217: collection.addMethod("POST");
218: collection.addPattern("/*");
219: collection.setName("default");
220: SecurityConstraint sc = new SecurityConstraint();
221: sc.addAuthRole("*");
222: sc.addCollection(collection);
223: sc.setAuthConstraint(true);
224: sc.setUserConstraint(transportGuarantee);
225: context.addConstraint(sc);
226: context.addSecurityRole("default");
227:
228: //Set the proper authenticator
229: if ("BASIC".equals(authMethod)) {
230: context.addValve(new BasicAuthenticator());
231: } else if ("DIGEST".equals(authMethod)) {
232: context.addValve(new DigestAuthenticator());
233: } else if ("CLIENT-CERT".equals(authMethod)) {
234: context.addValve(new SSLAuthenticator());
235: } else if ("NONE".equals(authMethod)) {
236: context.addValve(new NonLoginAuthenticator());
237: }
238: } else {
239: throw new IllegalArgumentException("Invalid authMethod: "
240: + authMethod);
241: }
242:
243: // Mark this as a dynamic context that should not be inspected by the TomcatWebAppBuilder
244: context.getServletContext()
245: .setAttribute(IGNORE_CONTEXT, "true");
246:
247: // build the servlet
248: Wrapper wrapper = context.createWrapper();
249: wrapper.setName("webservice");
250: wrapper.setServletClass(WsServlet.class.getName());
251: setWsContainer(context, wrapper, httpListener);
252: wrapper.addMapping("/*");
253:
254: // add add servlet to context
255: context.addChild(wrapper);
256: context.addServletMapping("/*", "webservice");
257:
258: // add context to host
259: host.addChild(context);
260: webserviceContexts.put(path, context);
261:
262: // register wsdl locations for service-ref resolution
263: List<String> addresses = new ArrayList<String>();
264: for (Connector connector : connectors) {
265: URI address = new URI(connector.getScheme(), null, host
266: .getName(), connector.getPort(), path, null, null);
267: addresses.add(address.toString());
268: }
269: return addresses;
270: }
271:
272: public void removeWsContainer(String path) {
273: if (path == null)
274: return;
275:
276: // assure context root with a leading slash
277: if (!path.startsWith("/"))
278: path = "/" + path;
279:
280: StandardContext context = webserviceContexts.remove(path);
281: try {
282: context.stop();
283: context.destroy();
284: } catch (Exception e) {
285: throw new RuntimeException(e);
286: }
287: Host host = (Host) context.getParent();
288: host.removeChild(context);
289: }
290:
291: private void setWsContainer(Context context, Wrapper wrapper,
292: HttpListener wsContainer) {
293: // Make up an ID for the WebServiceContainer
294: // put a reference the ID in the init-params
295: // put the WebServiceContainer in the webapp context keyed by its ID
296: String webServicecontainerID = wrapper.getName()
297: + WsServlet.WEBSERVICE_CONTAINER
298: + wsContainer.hashCode();
299: context.getServletContext().setAttribute(webServicecontainerID,
300: wsContainer);
301: wrapper.addInitParameter(WsServlet.WEBSERVICE_CONTAINER,
302: webServicecontainerID);
303: }
304: }
|