1 /*
2 * $Id: StrutsXmlConfigurationProvider.java 762875 2009-04-07 17:56:30Z musachy $
3 *
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 package org.apache.struts2.config;
23
24 import java.io.File;
25 import java.io.IOException;
26 import java.net.MalformedURLException;
27 import java.net.URL;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Map;
33
34 import javax.servlet.ServletContext;
35
36 import com.opensymphony.xwork2.ActionContext;
37 import com.opensymphony.xwork2.config.ConfigurationException;
38 import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
39 import com.opensymphony.xwork2.inject.ContainerBuilder;
40 import com.opensymphony.xwork2.inject.Context;
41 import com.opensymphony.xwork2.inject.Factory;
42 import com.opensymphony.xwork2.util.location.LocatableProperties;
43 import com.opensymphony.xwork2.util.logging.Logger;
44 import com.opensymphony.xwork2.util.logging.LoggerFactory;
45
46 /**
47 * Override Xwork class so we can use an arbitrary config file
48 */
49 public class StrutsXmlConfigurationProvider extends XmlConfigurationProvider {
50
51 private static final Logger LOG = LoggerFactory.getLogger(StrutsXmlConfigurationProvider.class);
52 private File baseDir = null;
53 private String filename;
54 private String reloadKey;
55 private ServletContext servletContext;
56
57 /**
58 * Constructs the configuration provider
59 *
60 * @param errorIfMissing If we should throw an exception if the file can't be found
61 */
62 public StrutsXmlConfigurationProvider(boolean errorIfMissing) {
63 this("struts.xml", errorIfMissing, null);
64 }
65
66 /**
67 * Constructs the configuration provider
68 *
69 * @param filename The filename to look for
70 * @param errorIfMissing If we should throw an exception if the file can't be found
71 * @param ctx Our ServletContext
72 */
73 public StrutsXmlConfigurationProvider(String filename, boolean errorIfMissing, ServletContext ctx) {
74 super(filename, errorIfMissing);
75 this.servletContext = ctx;
76 this.filename = filename;
77 reloadKey = "configurationReload-"+filename;
78 Map<String,String> dtdMappings = new HashMap<String,String>(getDtdMappings());
79 dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.0//EN", "struts-2.0.dtd");
80 dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.1//EN", "struts-2.1.dtd");
81 dtdMappings.put("-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN", "struts-2.1.7.dtd");
82 setDtdMappings(dtdMappings);
83 File file = new File(filename);
84 if (file.getParent() != null) {
85 this.baseDir = file.getParentFile();
86 }
87 }
88
89 /* (non-Javadoc)
90 * @see com.opensymphony.xwork2.config.providers.XmlConfigurationProvider#register(com.opensymphony.xwork2.inject.ContainerBuilder, java.util.Properties)
91 */
92 @Override
93 public void register(ContainerBuilder containerBuilder, LocatableProperties props) throws ConfigurationException {
94 if (servletContext != null && !containerBuilder.contains(ServletContext.class)) {
95 containerBuilder.factory(ServletContext.class, new Factory<ServletContext>() {
96 public ServletContext create(Context context) throws Exception {
97 return servletContext;
98 }
99 });
100 }
101 super.register(containerBuilder, props);
102 }
103
104 /* (non-Javadoc)
105 * @see com.opensymphony.xwork2.config.providers.XmlConfigurationProvider#init(com.opensymphony.xwork2.config.Configuration)
106 */
107 @Override
108 public void loadPackages() {
109 ActionContext ctx = ActionContext.getContext();
110 ctx.put(reloadKey, Boolean.TRUE);
111 super.loadPackages();
112 }
113
114 /**
115 * Look for the configuration file on the classpath and in the file system
116 *
117 * @param fileName The file name to retrieve
118 * @see com.opensymphony.xwork2.config.providers.XmlConfigurationProvider#getConfigurationUrls
119 */
120 @Override
121 protected Iterator<URL> getConfigurationUrls(String fileName) throws IOException {
122 URL url = null;
123 if (baseDir != null) {
124 url = findInFileSystem(fileName);
125 if (url == null) {
126 return super.getConfigurationUrls(fileName);
127 }
128 }
129 if (url != null) {
130 List<URL> list = new ArrayList<URL>();
131 list.add(url);
132 return list.iterator();
133 } else {
134 return super.getConfigurationUrls(fileName);
135 }
136 }
137
138 protected URL findInFileSystem(String fileName) throws IOException {
139 URL url = null;
140 File file = new File(fileName);
141 if (LOG.isDebugEnabled()) {
142 LOG.debug("Trying to load file " + file);
143 }
144
145 // Trying relative path to original file
146 if (!file.exists()) {
147 file = new File(baseDir, fileName);
148 }
149 if (file.exists()) {
150 try {
151 url = file.toURI().toURL();
152 } catch (MalformedURLException e) {
153 throw new IOException("Unable to convert "+file+" to a URL");
154 }
155 }
156 return url;
157 }
158
159 /**
160 * Overrides needs reload to ensure it is only checked once per request
161 */
162 @Override
163 public boolean needsReload() {
164 ActionContext ctx = ActionContext.getContext();
165 if (ctx != null) {
166 return ctx.get(reloadKey) == null && super.needsReload();
167 } else {
168 return super.needsReload();
169 }
170
171 }
172
173 public String toString() {
174 return ("Struts XML configuration provider ("+filename+")");
175 }
176 }