1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.common.xml;
20
21 import java.io.BufferedInputStream;
22 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.net.URL;
26 import java.net.URLConnection;
27
28 import org.apache.commons.io.IOUtils;
29 import org.apache.logging.log4j.LogManager;
30 import org.apache.logging.log4j.Logger;
31 import org.jdom2.JDOMException;
32 import org.mycore.common.MCRCache;
33 import org.mycore.common.MCRClassTools;
34 import org.mycore.common.config.MCRConfiguration2;
35 import org.mycore.common.config.MCRConfigurationDir;
36 import org.mycore.common.content.MCRContent;
37 import org.mycore.common.content.MCRURLContent;
38
39
40
41
42
43
44
45
46
47 public class MCRXMLResource {
48
49 private static final MCRCache<String, CacheEntry> RESOURCE_CACHE = new MCRCache<>(
50 MCRConfiguration2.getInt("MCR.MCRXMLResource.Cache.Size").orElse(100),
51 "XML resources");
52
53 private static MCRXMLResource instance = new MCRXMLResource();
54
55 private static Logger LOGGER = LogManager.getLogger(MCRXMLResource.class);
56
57 private MCRXMLResource() {
58 }
59
60
61
62
63 public static MCRXMLResource instance() {
64 return instance;
65 }
66
67 private static URLConnection getResourceURLConnection(String name, ClassLoader classLoader) throws IOException {
68 LOGGER.debug("Reading xml from classpath resource {}", name);
69 URL url = MCRConfigurationDir.getConfigResource(name, classLoader);
70 LOGGER.debug("Resource URL:{}", url);
71 if (url == null) {
72 return null;
73 }
74 return url.openConnection();
75 }
76
77 private static MCRContent getDocument(URL url) {
78 return new MCRURLContent(url);
79 }
80
81 private static void closeURLConnection(URLConnection con) throws IOException {
82 if (con == null) {
83 return;
84 }
85 con.getInputStream().close();
86 }
87
88 public URL getURL(String name) throws IOException {
89 return getURL(name, MCRClassTools.getClassLoader());
90 }
91
92 public URL getURL(String name, ClassLoader classLoader) throws IOException {
93 URLConnection con = getResourceURLConnection(name, classLoader);
94 if (con == null) {
95 return null;
96 }
97 try {
98 return con.getURL();
99 } finally {
100 closeURLConnection(con);
101 }
102 }
103
104
105
106
107
108
109
110
111 public MCRContent getResource(String name) throws IOException, JDOMException {
112 return getResource(name, MCRClassTools.getClassLoader());
113 }
114
115
116
117
118
119
120
121
122 public byte[] getRawResource(String name) throws IOException {
123 return getRawResource(name, MCRClassTools.getClassLoader());
124 }
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141 public MCRContent getResource(String name, ClassLoader classLoader) throws IOException {
142 ResourceModifiedHandle modifiedHandle = getModifiedHandle(name, classLoader, 10000);
143 CacheEntry entry = RESOURCE_CACHE.getIfUpToDate(name, modifiedHandle);
144 URL resolvedURL = modifiedHandle.getURL();
145 if (entry != null && (resolvedURL == null || entry.resourceURL.equals(resolvedURL))) {
146 LOGGER.debug("Using cached resource {}", name);
147 return entry.content;
148 }
149 if (resolvedURL == null) {
150 LOGGER.warn("Could not resolve resource: {}", name);
151 return null;
152 }
153 entry = new CacheEntry();
154 RESOURCE_CACHE.put(name, entry);
155 entry.resourceURL = resolvedURL;
156 entry.content = getDocument(entry.resourceURL);
157 return entry.content;
158 }
159
160 public ResourceModifiedHandle getModifiedHandle(String name, ClassLoader classLoader, long checkPeriod) {
161 return new ResourceModifiedHandle(name, classLoader, checkPeriod);
162 }
163
164
165
166
167
168
169
170
171
172
173
174
175
176 public byte[] getRawResource(String name, ClassLoader classLoader) throws IOException {
177 URLConnection con = getResourceURLConnection(name, classLoader);
178 if (con == null) {
179 return null;
180 }
181 try (ByteArrayOutputStream baos = new ByteArrayOutputStream(64 * 1024);
182 InputStream in = new BufferedInputStream(con.getInputStream())) {
183 IOUtils.copy(in, baos);
184 return baos.toByteArray();
185 } finally {
186 closeURLConnection(con);
187 }
188 }
189
190 public long getLastModified(String name, ClassLoader classLoader) throws IOException {
191 URLConnection con = getResourceURLConnection(name, classLoader);
192 try {
193 return con == null ? -1 : con.getLastModified();
194 } finally {
195 closeURLConnection(con);
196 }
197 }
198
199 public boolean exists(String name, ClassLoader classLoader) throws IOException {
200 final URLConnection resourceURLConnection = getResourceURLConnection(name, classLoader);
201 try {
202 return resourceURLConnection != null;
203 } finally {
204 closeURLConnection(resourceURLConnection);
205 }
206 }
207
208 private static class CacheEntry {
209 URL resourceURL;
210
211 MCRContent content;
212 }
213
214 public static class ResourceModifiedHandle implements MCRCache.ModifiedHandle {
215 private long checkPeriod;
216
217 private String name;
218
219 private ClassLoader classLoader;
220
221 private URL resolvedURL;
222
223 public ResourceModifiedHandle(String name, ClassLoader classLoader, long checkPeriod) {
224 this.name = name;
225 this.classLoader = classLoader;
226 this.checkPeriod = checkPeriod;
227 }
228
229 public URL getURL() {
230 return this.resolvedURL == null ? MCRConfigurationDir.getConfigResource(name, classLoader)
231 : this.resolvedURL;
232 }
233
234 @Override
235 public long getCheckPeriod() {
236 return checkPeriod;
237 }
238
239 @Override
240 public long getLastModified() throws IOException {
241 URLConnection con = getResourceURLConnection(name, classLoader);
242 if (con == null) {
243 return -1;
244 }
245 try {
246 long lastModified = con.getLastModified();
247 resolvedURL = con.getURL();
248 LOGGER.debug("{} last modified: {}", name, lastModified);
249 return lastModified;
250 } finally {
251 closeURLConnection(con);
252 }
253 }
254
255 }
256 }