001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.jk.config;
019:
020: import java.io.File;
021: import java.io.FileWriter;
022: import java.io.IOException;
023: import java.io.PrintWriter;
024: import java.util.Date;
025:
026: import org.apache.catalina.Context;
027:
028: /**
029: Generates automatic IIS isapi_redirect configurations based on
030: the Tomcat server.xml settings and the war contexts
031: initialized during startup.
032: <p>
033: This config interceptor is enabled by inserting an IISConfig
034: element in the <b><ContextManager></b> tag body inside
035: the server.xml file like so:
036: <pre>
037: * < ContextManager ... >
038: * ...
039: * <<b>IISConfig</b> <i>options</i> />
040: * ...
041: * < /ContextManager >
042: </pre>
043: where <i>options</i> can include any of the following attributes:
044: <ul>
045: <li><b>configHome</b> - default parent directory for the following paths.
046: If not set, this defaults to TOMCAT_HOME. Ignored
047: whenever any of the following paths is absolute.
048: </li>
049: <li><b>regConfig</b> - path to use for writing IIS isapi_redirect registry
050: file. If not set, defaults to
051: "conf/auto/iis_redirect.reg".</li>
052: <li><b>workersConfig</b> - path to workers.properties file used by
053: isapi_redirect. If not set, defaults to
054: "conf/jk/workers.properties".</li>
055: <li><b>uriConfig</b> - path to use for writing IIS isapi_redirect uriworkermap
056: file. If not set, defaults to
057: "conf/auto/uriworkermap.properties".</li>
058: <li><b>jkLog</b> - path to log file to be used by isapi_redirect.</li>
059: <li><b>jkDebug</b> - Loglevel setting. May be debug, info, error, or emerg.
060: If not set, defaults to emerg.</li>
061: <li><b>jkWorker</b> The desired worker. Must be set to one of the workers
062: defined in the workers.properties file. "ajp12", "ajp13"
063: or "inprocess" are the workers found in the default
064: workers.properties file. If not specified, defaults
065: to "ajp13" if an Ajp13Interceptor is in use, otherwise
066: it defaults to "ajp12".</li>
067: <li><b>forwardAll</b> - If true, forward all requests to Tomcat. This helps
068: insure that all the behavior configured in the web.xml
069: file functions correctly. If false, let IIS serve
070: static resources assuming it has been configured
071: to do so. The default is true.
072: Warning: When false, some configuration in
073: the web.xml may not be duplicated in IIS.
074: Review the uriworkermap file to see what
075: configuration is actually being set in IIS.</li>
076: <li><b>noRoot</b> - If true, the root context is not mapped to
077: Tomcat. If false and forwardAll is true, all requests
078: to the root context are mapped to Tomcat. If false and
079: forwardAll is false, only JSP and servlets requests to
080: the root context are mapped to Tomcat. When false,
081: to correctly serve Tomcat's root context you must also
082: modify the Home Directory setting in IIS
083: to point to Tomcat's root context directory.
084: Otherwise some content, such as the root index.html,
085: will be served by IIS before isapi_redirect gets a chance
086: to claim the request and pass it to Tomcat.
087: The default is true.</li>
088: </ul>
089: <p>
090: @author Costin Manolache
091: @author Larry Isaacs
092: @author Gal Shachor
093: @author Bill Barker
094: */
095: public class IISConfig extends BaseJkConfig {
096: private static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory
097: .getLog(IISConfig.class);
098:
099: public static final String WORKERS_CONFIG = "/conf/jk/workers.properties";
100: public static final String URI_WORKERS_MAP_CONFIG = "/conf/auto/uriworkermap.properties";
101: public static final String ISAPI_LOG_LOCATION = "/logs/iis_redirect.log";
102: public static final String ISAPI_REG_FILE = "/conf/auto/iis_redirect.reg";
103:
104: private File regConfig = null;
105: private File uriConfig = null;
106:
107: public IISConfig() {
108: }
109:
110: //-------------------- Properties --------------------
111:
112: /**
113: set the path to the output file for the auto-generated
114: isapi_redirect registry file. If this path is relative
115: then getRegConfig() will resolve it absolutely against
116: the getConfigHome() path.
117: <p>
118: @param path String path to a file
119: */
120: public void setRegConfig(String path) {
121: regConfig = (path == null) ? null : new File(path);
122: }
123:
124: /**
125: set a path to the uriworkermap.properties file.
126: @param path String path to uriworkermap.properties file
127: */
128: public void setUriConfig(String path) {
129: uriConfig = (path == null ? null : new File(path));
130: }
131:
132: // -------------------- Initialize/guess defaults --------------------
133:
134: /** Initialize defaults for properties that are not set
135: explicitely
136: */
137: protected void initProperties() {
138: super .initProperties();
139:
140: regConfig = getConfigFile(regConfig, configHome, ISAPI_REG_FILE);
141: workersConfig = getConfigFile(workersConfig, configHome,
142: WORKERS_CONFIG);
143: uriConfig = getConfigFile(uriConfig, configHome,
144: URI_WORKERS_MAP_CONFIG);
145: jkLog = getConfigFile(jkLog, configHome, ISAPI_LOG_LOCATION);
146: }
147:
148: // -------------------- Generate config --------------------
149:
150: protected PrintWriter getWriter() throws IOException {
151: String abUriConfig = uriConfig.getAbsolutePath();
152: return new PrintWriter(new FileWriter(abUriConfig, append));
153: }
154:
155: protected boolean generateJkHead(PrintWriter mod_jk) {
156: try {
157: PrintWriter regfile = new PrintWriter(new FileWriter(
158: regConfig));
159: log.info("Generating IIS registry file = " + regConfig);
160: generateRegistrySettings(regfile);
161: regfile.close();
162: } catch (IOException iex) {
163: log.warn("Unable to generate registry file " + regConfig);
164: return false;
165: }
166: log.info("Generating IIS URI worker map file = " + uriConfig);
167: generateUriWorkerHeader(mod_jk);
168: return true;
169: }
170:
171: // -------------------- Config sections --------------------
172:
173: /** Writes the registry settings required by the IIS connector
174: */
175: private void generateRegistrySettings(PrintWriter regfile) {
176: regfile.println("REGEDIT4");
177: regfile.println();
178: regfile
179: .println("[HKEY_LOCAL_MACHINE\\SOFTWARE\\Apache Software Foundation\\Jakarta Isapi Redirector\\1.0]");
180: regfile
181: .println("\"extension_uri\"=\"/jakarta/isapi_redirect.dll\"");
182: regfile.println("\"log_file\"=\""
183: + dubleSlash(jkLog.toString()) + "\"");
184: regfile.println("\"log_level\"=\"" + jkDebug + "\"");
185: regfile.println("\"worker_file\"=\""
186: + dubleSlash(workersConfig.toString()) + "\"");
187: regfile.println("\"worker_mount_file\"=\""
188: + dubleSlash(uriConfig.toString()) + "\"");
189: }
190:
191: /** Writes the header information to the uriworkermap file
192: */
193: private void generateUriWorkerHeader(PrintWriter uri_worker) {
194: uri_worker
195: .println("###################################################################");
196: uri_worker.println("# Auto generated configuration. Dated: "
197: + new Date());
198: uri_worker
199: .println("###################################################################");
200: uri_worker.println();
201:
202: uri_worker.println("#");
203: uri_worker
204: .println("# Default worker to be used through our mappings");
205: uri_worker.println("#");
206: uri_worker.println("default.worker=" + jkWorker);
207: uri_worker.println();
208: }
209:
210: /** Forward all requests for a context to tomcat.
211: The default.
212: */
213: protected void generateStupidMappings(Context context,
214: PrintWriter uri_worker) {
215: String ctxPath = context.getPath();
216: String nPath = ("".equals(ctxPath)) ? "/" : ctxPath;
217:
218: if (noRoot && "".equals(ctxPath)) {
219: log.debug("Ignoring root context in forward-all mode ");
220: return;
221: }
222:
223: // map all requests for this context to Tomcat
224: uri_worker.println(nPath + "=$(default.worker)");
225: if ("".equals(ctxPath)) {
226: uri_worker.println(nPath + "*=$(default.worker)");
227: uri_worker
228: .println("# Note: To correctly serve the Tomcat's root context, IIS's Home Directory must");
229: uri_worker.println("# must be set to: \""
230: + getAbsoluteDocBase(context) + "\"");
231: } else
232: uri_worker.println(nPath + "/*=$(default.worker)");
233: }
234:
235: protected void generateContextMappings(Context context,
236: PrintWriter uri_worker) {
237: String ctxPath = context.getPath();
238: String nPath = ("".equals(ctxPath)) ? "/" : ctxPath;
239:
240: if (noRoot && "".equals(ctxPath)) {
241: log.debug("Ignoring root context in forward-all mode ");
242: return;
243: }
244:
245: // Static files will be served by IIS
246: uri_worker.println();
247: uri_worker
248: .println("#########################################################");
249: uri_worker.println("# Auto configuration for the " + nPath
250: + " context.");
251: uri_worker
252: .println("#########################################################");
253: uri_worker.println();
254:
255: // Static mappings are not set in uriworkermap, but must be set with IIS admin.
256:
257: // InvokerInterceptor - it doesn't have a container,
258: // but it's implemented using a special module.
259:
260: // XXX we need to better collect all mappings
261:
262: if (context.getLoginConfig() != null) {
263: String loginPage = context.getLoginConfig().getLoginPage();
264: if (loginPage != null) {
265: int lpos = loginPage.lastIndexOf("/");
266: String jscurl = loginPage.substring(0, lpos + 1)
267: + "j_security_check";
268: addMapping(ctxPath, jscurl, uri_worker);
269: }
270: }
271: String[] servletMaps = context.findServletMappings();
272: for (int ii = 0; ii < servletMaps.length; ii++) {
273: addMapping(ctxPath, servletMaps[ii], uri_worker);
274: }
275: }
276:
277: /** Add an IIS extension mapping.
278: */
279: protected boolean addMapping(String ctxPath, String ext,
280: PrintWriter uri_worker) {
281: if (log.isDebugEnabled())
282: log.debug("Adding extension map for " + ctxPath + "/*."
283: + ext);
284: if (!ext.startsWith("/"))
285: ext = "/" + ext;
286: if (ext.length() > 1)
287: uri_worker.println(ctxPath + "/*." + ext
288: + "=$(default.worker)");
289: return true;
290: }
291:
292: /** Add a fulling specified IIS mapping.
293: */
294: protected boolean addMapping(String fullPath, PrintWriter uri_worker) {
295: if (log.isDebugEnabled())
296: log.debug("Adding map for " + fullPath);
297: uri_worker.println(fullPath + "=$(default.worker)");
298: return true;
299: }
300:
301: // -------------------- Utils --------------------
302:
303: private String dubleSlash(String in) {
304: StringBuffer sb = new StringBuffer();
305:
306: for (int i = 0; i < in.length(); i++) {
307: char ch = in.charAt(i);
308: if ('\\' == ch) {
309: sb.append("\\\\");
310: } else {
311: sb.append(ch);
312: }
313: }
314:
315: return sb.toString();
316: }
317:
318: }
|