001: /*******************************************************************************
002: * Portions created by Sebastian Thomschke are copyright (c) 2005-2007 Sebastian
003: * Thomschke.
004: *
005: * All Rights Reserved. This program and the accompanying materials
006: * are made available under the terms of the Eclipse Public License v1.0
007: * which accompanies this distribution, and is available at
008: * http://www.eclipse.org/legal/epl-v10.html
009: *
010: * Contributors:
011: * Sebastian Thomschke - initial implementation.
012: * Makkari - live connect support.
013: *******************************************************************************/package net.sf.oval.constraint;
014:
015: import java.io.IOException;
016: import java.net.HttpURLConnection;
017: import java.net.URI;
018: import java.net.URL;
019: import java.net.URLConnection;
020:
021: import net.sf.oval.Validator;
022: import net.sf.oval.configuration.annotation.AbstractAnnotationCheck;
023: import net.sf.oval.context.OValContext;
024: import net.sf.oval.internal.Log;
025:
026: /**
027: * @author Sebastian Thomschke
028: */
029: public class AssertURLCheck extends AbstractAnnotationCheck<AssertURL> {
030: /**
031: * http://en.wikipedia.org/wiki/URI_scheme
032: *
033: * @author Sebastian Thomschke
034: *
035: */
036: public static enum URIScheme {
037: FTP("ftp"), HTTP("http"), HTTPS("https");
038:
039: private final String scheme;
040:
041: private URIScheme(final String scheme) {
042: this .scheme = scheme;
043: }
044:
045: /**
046: * @return the scheme
047: */
048: public String getScheme() {
049: return scheme;
050: }
051:
052: @Override
053: public String toString() {
054: return scheme;
055: }
056: }
057:
058: private static final long serialVersionUID = 1L;
059:
060: private final Log LOG = Log.getLog(AssertURLCheck.class);
061:
062: /**
063: * Specifies if a connection to the URL should be attempted to verify its validity.
064: */
065: private boolean connect = false;
066:
067: /**
068: * Specifies the allowed URL schemes.
069: */
070: private URIScheme[] permittedURISchemes;
071:
072: private boolean canConnect(final String url) {
073: try {
074: final URL theURL = new URL(url);
075: final URLConnection conn = theURL.openConnection();
076: conn.connect();
077: conn.getInputStream().close();
078: if (conn instanceof HttpURLConnection) {
079: final HttpURLConnection httpConnection = (HttpURLConnection) conn;
080: final int rc = httpConnection.getResponseCode();
081:
082: if (rc < HttpURLConnection.HTTP_BAD_REQUEST)
083: return true;
084: LOG.trace("Connecting failed with HTTP response code "
085: + rc);
086: return false;
087: }
088: } catch (final IOException e) {
089: LOG.trace("Connecting failed with exception", e);
090: return false;
091: }
092: return true;
093: }
094:
095: @Override
096: public void configure(final AssertURL constraintAnnotation) {
097: super .configure(constraintAnnotation);
098: setConnect(constraintAnnotation.connect());
099: setPermittedURISchemes(constraintAnnotation
100: .permittedURISchemes());
101: }
102:
103: /**
104: * Gets the allowed URL schemes.
105: * @return the permittedURISchemes
106: */
107: public URIScheme[] getPermittedURISchemes() {
108: return permittedURISchemes == null ? null : permittedURISchemes
109: .clone();
110: }
111:
112: /**
113: * Specifies if a connection to the URL should be attempted to verify its validity.
114: *
115: * @return the connect
116: */
117: public boolean isConnect() {
118: return connect;
119: }
120:
121: public boolean isSatisfied(final Object validatedObject,
122: final Object value, final OValContext context,
123: final Validator validator) {
124: if (value == null)
125: return true;
126:
127: final String URIString = value.toString();
128:
129: try {
130: // By constructing a java.net.URI object, the string representing the URI will be parsed against RFC 2396.
131: // In case of non compliance a java.net.URISyntaxException will be thrown
132: final URI uri = new URI(URIString);
133:
134: // Make sure that the URI contains: [scheme; scheme-specific-part]
135: final String scheme = uri.getScheme();
136: if (scheme == null
137: || uri.getRawSchemeSpecificPart() == null) {
138: LOG
139: .trace("URI scheme or scheme-specific-part not specified");
140: return false;
141: }
142:
143: // Check whether the URI scheme is supported
144: if (!isURISchemeValid(scheme.toLowerCase()))
145: return false;
146:
147: // If the connect flag is true then attempt to connect to the URL
148: if (connect)
149: return canConnect(URIString);
150: } catch (final java.net.URISyntaxException ex) {
151: LOG
152: .trace("URI scheme or scheme-specific-part not specified");
153: return false;
154: }
155:
156: return true;
157: }
158:
159: private boolean isURISchemeValid(final String url) {
160: if (permittedURISchemes != null) {
161: for (final URIScheme scheme : permittedURISchemes) {
162: if (url.startsWith(scheme.getScheme()))
163: return true;
164: }
165: }
166: return false;
167: }
168:
169: /**
170: * Specifies if a connection to the URL should be attempted to verify its validity.
171: *
172: * @param connect the connect to set
173: */
174: public void setConnect(final boolean connect) {
175: this .connect = connect;
176: }
177:
178: /**
179: * Specifies the allowed URL schemes.
180: *
181: * @param permittedURISchemes the permittedURISchemes to set
182: */
183: public void setPermittedURISchemes(
184: final URIScheme[] permittedURISchemes) {
185: this.permittedURISchemes = permittedURISchemes == null ? null
186: : permittedURISchemes.clone();
187: }
188: }
|