source: CMDIValidator/trunk/cmdi-validator-core/src/main/java/eu/clarin/cmdi/validator/extensions/CheckHandlesExtension.java @ 5402

Last change on this file since 5402 was 5402, checked in by Oliver Schonefeld, 10 years ago
  • some more re-factoring and renaming
  • Property svn:eol-style set to native
File size: 9.1 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.extensions;
18
19import java.io.IOException;
20import java.net.URI;
21import java.net.URISyntaxException;
22
23import org.apache.http.HttpStatus;
24import net.sf.saxon.s9api.SaxonApiException;
25import net.sf.saxon.s9api.XPathCompiler;
26import net.sf.saxon.s9api.XPathExecutable;
27import net.sf.saxon.s9api.XPathSelector;
28import net.sf.saxon.s9api.XdmItem;
29import net.sf.saxon.s9api.XdmNode;
30import eu.clarin.cmdi.validator.CMDIValidatorException;
31import eu.clarin.cmdi.validator.CMDIValidatorExtension;
32import eu.clarin.cmdi.validator.CMDIValidatorInitException;
33import eu.clarin.cmdi.validator.CMDIWriteableValidationReport;
34import eu.clarin.cmdi.validator.utils.HandleResolver;
35import eu.clarin.cmdi.validator.utils.LocationUtils;
36
37public class CheckHandlesExtension extends CMDIValidatorExtension {
38    private static final String XPATH = "//*:ResourceProxy[*:ResourceType/text() = 'Resource' or *:ResourceType/text() = 'Metadata']/*:ResourceRef";
39    private static final String HDL_SCHEME = "hdl";
40    private static final String HDL_PROXY_HTTP = "http";
41    private static final String HDL_PROXY_HTTPS = "https";
42    private static final String HDL_PROXY_HOST = "hdl.handle.net";
43    private static final String URN_SCHEME = "urn";
44    private final boolean resolveHandles;
45    private HandleResolver resolver = null;
46    private XPathExecutable xpath;
47
48
49    public CheckHandlesExtension(boolean resolveHandles) {
50        this.resolveHandles = resolveHandles;
51    }
52
53
54    public boolean isResolvingHandles() {
55        return resolveHandles;
56    }
57
58
59    public HandleResolver.Statistics getStatistics() {
60        return (resolver != null) ? resolver.getStatistics() : null;
61    }
62
63
64    @Override
65    protected void doInitialize() throws CMDIValidatorInitException {
66        if (resolveHandles) {
67            this.resolver = new HandleResolver();
68        }
69
70        try {
71            final XPathCompiler compiler = processor.newXPathCompiler();
72            this.xpath = compiler.compile(XPATH);
73        } catch (SaxonApiException e) {
74            throw new CMDIValidatorInitException(
75                    "error initializing check handle extension", e);
76        }
77    }
78
79
80    @Override
81    public void validate(final XdmNode document,
82            final CMDIWriteableValidationReport report)
83            throws CMDIValidatorException {
84        try {
85            XPathSelector selector = xpath.load();
86            selector.setContextItem(document);
87            for (XdmItem item : selector) {
88                String handle = null;
89                final int line   = LocationUtils.getLineNumber(item);
90                final int column = LocationUtils.getColumnNumber(item);
91                final String h = item.getStringValue();
92                if (h != null) {
93                    handle = h.trim();
94                    if (handle.isEmpty()) {
95                        handle = null;
96                    } else {
97                        if (!handle.equals(h)) {
98                            report.reportWarning(line, column, "handle '" + h +
99                                    "' contains leading or tailing spaces " +
100                                    "within <ResourceRef> element");
101                        }
102                    }
103                }
104
105                if (handle != null) {
106                    checkHandleURISyntax(report, handle, line, column);
107                } else {
108                    report.reportError(line, column,
109                            "invalid handle (<ResourceRef> was empty)");
110                }
111            }
112        } catch (SaxonApiException e) {
113            throw new CMDIValidatorException("failed to check handles", e);
114        }
115    }
116
117
118    private void checkHandleURISyntax(
119            final CMDIWriteableValidationReport report, final String handle,
120            final int line, final int column) throws CMDIValidatorException {
121        try {
122            final URI uri = new URI(handle);
123            if (HDL_SCHEME.equalsIgnoreCase(uri.getScheme())) {
124                String path = uri.getSchemeSpecificPart();
125                if (!path.startsWith("/")) {
126                    path = "/" + path;
127                }
128                try {
129                    final URI actionableURI =
130                            new URI(HDL_PROXY_HTTP, HDL_PROXY_HOST, path, null);
131                    checkHandleResolves(report, actionableURI, line, column);
132                } catch (URISyntaxException e) {
133                    /* should not happen */
134                    throw new CMDIValidatorException(
135                            "created an invalid URI", e);
136                }
137            } else if (URN_SCHEME.equals(uri.getScheme())) {
138                if (resolveHandles) {
139                    report.reportInfo(line, column, "PID '" + handle +
140                            "' skipped, because URN resolving is not supported");
141                } else {
142                    report.reportInfo(line, column, "PID '" + handle +
143                            "' skipped, because URN sytax checking is not supported");
144                }
145            } else if (HDL_PROXY_HTTP.equalsIgnoreCase(uri.getScheme()) ||
146                    HDL_PROXY_HTTPS.equalsIgnoreCase(uri.getScheme())) {
147                if (uri.getHost() != null) {
148                    if (!HDL_PROXY_HOST.equalsIgnoreCase(uri.getHost())) {
149                        report.reportError(line, column,
150                                "The URI of PID '" + handle +
151                                "' contains an unexpected host part of '" +
152                                uri.getHost() + "'");
153                    }
154                    checkHandleResolves(report, uri, line, column);
155                } else {
156                    report.reportError(line, column, "The URI of PID '" +
157                            handle + "' is missing the host part");
158                }
159            } else {
160                if (uri.getScheme() != null) {
161                    report.reportError(line, column,
162                            "The URI of PID '" + handle +
163                            "' contains an unexpected schema part of '" +
164                            uri.getScheme() + "'");
165                } else {
166                    report.reportError(line, column, "The URI of PID '" +
167                            handle + "' is missing a proper schema part");
168                }
169            }
170        } catch (URISyntaxException e) {
171            report.reportError(line, column, "PID '" + handle +
172                    "' is not a well-formed URI: " + e.getMessage());
173        }
174    }
175
176
177    private void checkHandleResolves(
178            final CMDIWriteableValidationReport result, final URI uri,
179            final int line, final int column) throws CMDIValidatorException {
180        if (resolver != null) {
181            try {
182                int code = resolver.resolve(uri);
183                switch (code) {
184                case HttpStatus.SC_OK:
185                    /* no special message in this case */
186                    break;
187                case HttpStatus.SC_UNAUTHORIZED:
188                    /* FALL-THROUGH */
189                case HttpStatus.SC_FORBIDDEN:
190                    result.reportInfo(line, column, "PID '" + uri +
191                            "' resolved to an access protected resource (" +
192                            code + ")");
193                    break;
194                case HttpStatus.SC_NOT_FOUND:
195                    result.reportError(line, column, "PID '" + uri +
196                            "' resolved to an non-existing resource (" +
197                            code + ")");
198                    break;
199                case HandleResolver.TIMEOUT:
200                    result.reportWarning(line, column,
201                            "Timeout while resolving PID '" + uri + "'");
202                    break;
203                case HandleResolver.UNKNOWN_HOST:
204                    result.reportWarning(line, column,
205                            "Unable to resolve host '" + uri.getHost() +
206                            "' while resolving PID '" + uri + "'");
207                    break;
208                case HandleResolver.ERROR:
209                    result.reportWarning(line, column,
210                            "An error occurred while resolving PID '" +
211                            uri + "'");
212                    break;
213                default:
214                    result.reportWarning(-line, column, "PID '" + uri +
215                            "' resolved with an unexpected result (" +
216                            code + ")");
217                    break;
218                } // switch
219            } catch (IOException e) {
220                throw new CMDIValidatorException(
221                        "error while resolving handle '" + uri + "'", e);
222            }
223        }
224    }
225
226} // CheckHandleExtension
Note: See TracBrowser for help on using the repository browser.