source: CMDIValidator/trunk/cmdi-validator-core/src/main/java/eu/clarin/cmdi/validator/utils/HandleResolver.java @ 5384

Last change on this file since 5384 was 5384, checked in by Oliver Schonefeld, 10 years ago
  • add license stuff
  • Property svn:eol-style set to native
File size: 5.7 KB
Line 
1/**
2 * This software is copyright (c) 2014 by
3 *  - Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
4 * This is free software. You can redistribute it
5 * and/or modify it under the terms described in
6 * the GNU General Public License v3 of which you
7 * should have received a copy. Otherwise you can download
8 * it from
9 *
10 *   http://www.gnu.org/licenses/gpl-3.0.txt
11 *
12 * @copyright Institut fuer Deutsche Sprache (http://www.ids-mannheim.de)
13 *
14 * @license http://www.gnu.org/licenses/gpl-3.0.txt
15 *  GNU General Public License v3
16 */
17package eu.clarin.cmdi.validator.utils;
18
19import java.io.IOException;
20import java.net.URI;
21import java.util.HashSet;
22import java.util.Set;
23
24import org.apache.http.HttpResponse;
25import org.apache.http.StatusLine;
26import org.apache.http.client.HttpClient;
27import org.apache.http.client.methods.HttpHead;
28import org.apache.http.client.params.ClientPNames;
29import org.apache.http.client.utils.HttpClientUtils;
30import org.apache.http.impl.client.DefaultHttpClient;
31import org.apache.http.params.CoreProtocolPNames;
32import org.apache.http.params.HttpParams;
33import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
35
36import eu.clarin.cmdi.validator.CMDIValidatorException;
37
38public class HandleResolver {
39    private static final Logger logger =
40            LoggerFactory.getLogger(HandleResolver.class);
41    public final int ERROR   = -1;
42    private final LRUCache<URI, Integer> cache =
43            new LRUCache<URI, Integer>(16 * 1024);
44    private final Set<URI> pending;
45    private final Object waiter = new Object();
46    private long cacheHits   = 0;
47    private long cacheMisses = 0;
48
49
50    public HandleResolver(final int threads) {
51        this.pending = new HashSet<URI>(threads * 2);
52    }
53
54
55    public long getCacheHits() {
56        return cacheHits;
57    }
58
59
60    public long getCacheMisses() {
61        return cacheMisses;
62    }
63
64
65    public int resolve(final URI handle) throws CMDIValidatorException {
66        if (handle == null) {
67            throw new NullPointerException("handle == null");
68        }
69        logger.debug("resolving '{}'", handle);
70        for (;;) {
71            boolean doResolve = false;
72            synchronized (cache) {
73                final Integer cached = cache.get(handle);
74                if (cached != null) {
75                    logger.trace("got cached result for '{}': {}",
76                            handle, cached);
77                    cacheHits++;
78                    return cached.intValue();
79                }
80
81                synchronized (pending) {
82                    if (!pending.contains(handle)) {
83                        cacheMisses++;
84                        doResolve = true;
85                        pending.add(handle);
86                    }
87                } // synchronized (pending)
88            } // synchronized (cache)
89
90            // either resolve in this thread of wait for pending resolve result
91            if (doResolve) {
92                int result = ERROR;
93                try {
94                    final HttpClient httpClient = newHttpClient();
95                    try {
96                        result = doResolve(handle, httpClient);
97                    } finally {
98                        HttpClientUtils.closeQuietly(httpClient);
99                    }
100                } catch (Throwable e) {
101                    throw new CMDIValidatorException(
102                            "error while resolving handle '" + handle + "'", e);
103                } finally {
104                    // cache result and notify other threads
105                    synchronized (cache) {
106                        logger.trace("caching result {} for '{}'",
107                                result, handle);
108                        cache.put(handle, Integer.valueOf(result));
109                        synchronized (pending) {
110                            pending.remove(handle);
111                            synchronized (waiter) {
112                                waiter.notifyAll();
113                            } // synchronized (waiter)
114                        } // synchronized (pending)
115                    } // synchronized (cache)
116                }
117                return result;
118            } else {
119                try {
120                    synchronized (waiter) {
121                        waiter.wait();
122                    } // synchronized (waiter)
123                } catch (InterruptedException e) {
124                    return ERROR;
125                }
126            }
127        } // for
128    }
129
130
131    private int doResolve(final URI handle, final HttpClient httpClient)
132            throws CMDIValidatorException {
133        logger.trace("performing HTTP request for '{}'", handle);
134        HttpHead request = null;
135        HttpResponse response = null;
136        try {
137            request = new HttpHead(handle);
138            response = httpClient.execute(request);
139
140            final StatusLine status = response.getStatusLine();
141            return status.getStatusCode();
142        } catch (IOException e) {
143            if (request != null) {
144                request.abort();
145            }
146            throw new CMDIValidatorException("error resolving handle '" +
147                    handle + "'", e);
148        } finally {
149            /* make sure to release allocated resources */
150            HttpClientUtils.closeQuietly(response);
151        }
152    }
153
154
155    private HttpClient newHttpClient() {
156        final HttpClient client = new DefaultHttpClient();
157        final HttpParams params = client.getParams();
158        params.setParameter(CoreProtocolPNames.USER_AGENT,
159                getClass().getName() + "/1.0");
160        params.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, Boolean.TRUE);
161        params.setBooleanParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);
162        params.setIntParameter(ClientPNames.MAX_REDIRECTS, 16);
163        return client;
164    }
165
166} // class HandleResolver
Note: See TracBrowser for help on using the repository browser.