001 /* 002 * Copyright 2002-2004 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.springframework.richclient.image; 017 018 import java.io.IOException; 019 import java.net.MalformedURLException; 020 import java.net.URL; 021 import java.net.URLConnection; 022 import java.net.URLStreamHandler; 023 import java.net.URLStreamHandlerFactory; 024 025 import org.apache.commons.logging.Log; 026 import org.apache.commons.logging.LogFactory; 027 import org.springframework.core.io.Resource; 028 import org.springframework.util.Assert; 029 import org.springframework.util.StringUtils; 030 031 /** 032 * <p> 033 * A URL protocol handler that resolves images from an ImageSource. 034 * </p> 035 * <p> 036 * The syntax of an "image:" URL is: <code>image:{imageKey}</code> 037 * </p> 038 * 039 * There are three methods to register/use this custom protocol: 040 * <ol> 041 * <li>Supply the URLStreamHandler when constructing your URL object.</li> 042 * <li>Create an URLStreamHandlerFactory and register it on the URL class by 043 * using the setURLStreamFactory method.</li> 044 * <li>Create the URLStreamHandler by naming it Handler and placing it in a 045 * package which ends in the name if the protocol. Then register the package 046 * prefix before the protocol name by supplying it to the vm with the property 047 * -Djava.protocol.handler.pkgs. (thus setting it to eg 'my.company.protocols', 048 * your protocol is named image and your class name must be Handler which lives 049 * in package 'my.company.protocols.image') Multiple packages can be supplied by 050 * separating them with a '|'.</li> 051 * </ol> 052 * 053 * Now all of these have drawbacks: 054 * 055 * <ol> 056 * <li>obviously you don't want to construct each URL object with its specific 057 * handler.</li> 058 * <li>the factory can be set only once, if set twice an exception will be 059 * thrown. This was the initial error of this issue.</li> 060 * <li>you need to supply this system parameter at startup. The static method 061 * in the image Handler can only be used if no URL was created before and the 062 * system parameter wasn't read yet.</li> 063 * </ol> 064 * 065 * <p> 066 * We recommend that you use the system parameter at startup to ensure that the 067 * handler is registered: 068 * </p> 069 * 070 * <pre> 071 * -Djava.protocol.handler.pkgs=org.springframework.richclient 072 * </pre> 073 * 074 * <p> 075 * A static method {@link #installImageUrlHandler} is provided that extends the 076 * system property and includes the 'org.springframework.richclient'. This 077 * method can also be triggered by creating an imageSource using 078 * {@link DefaultImageSource#DefaultImageSource(boolean, java.util.Map)}. Note 079 * that this will only work if the system property isn't already read. If an URL 080 * was created and an {@link URLStreamHandlerFactory} is available, extending 081 * the system property won't have any effect. 082 * </p> 083 * 084 * @author Oliver Hutchison 085 * @author Jan Hoskens 086 * 087 */ 088 public class Handler extends URLStreamHandler { 089 090 private static final Log logger = LogFactory.getLog(Handler.class); 091 092 private static ImageSource urlHandlerImageSource; 093 094 /** 095 * Installs this class as a handler for the "image:" protocol. Images will 096 * be resolved from the provided image source. 097 */ 098 public static void installImageUrlHandler(ImageSource urlHandlerImageSource) { 099 Assert.notNull(urlHandlerImageSource); 100 101 Handler.urlHandlerImageSource = urlHandlerImageSource; 102 103 try { 104 // System properties should be set at JVM startup 105 // Testcases in IDEA/Eclipse are at JVM startup, but not in Maven's 106 // surefire... 107 // TODO this entire implementation should be changed with a 108 // java.net.URLStreamHandlerFactory instead. 109 String packagePrefixList = System.getProperty("java.protocol.handler.pkgs"); 110 String newPackagePrefixList = null; 111 String orgSpringFrameworkRichclientString = "org.springframework.richclient"; 112 if (packagePrefixList == null || packagePrefixList.equals("")) { 113 newPackagePrefixList = orgSpringFrameworkRichclientString; 114 } 115 else if (("|" + packagePrefixList + "|").indexOf("|" + orgSpringFrameworkRichclientString + "|") < 0) { 116 newPackagePrefixList = packagePrefixList + "|" + orgSpringFrameworkRichclientString; 117 } 118 if (newPackagePrefixList != null) { 119 System.setProperty("java.protocol.handler.pkgs", newPackagePrefixList); 120 } 121 } 122 catch (SecurityException e) { 123 logger.warn("Unable to install image URL handler", e); 124 Handler.urlHandlerImageSource = null; 125 } 126 } 127 128 /** 129 * Creates an instance of <code>Handler</code>. 130 */ 131 public Handler() { 132 } 133 134 protected URLConnection openConnection(URL url) throws IOException { 135 if (!StringUtils.hasText(url.getPath())) { 136 throw new MalformedURLException("must provide an image key."); 137 } 138 else if (StringUtils.hasText(url.getHost())) { 139 throw new MalformedURLException("host part should be empty."); 140 } 141 else if (url.getPort() != -1) { 142 throw new MalformedURLException("port part should be empty."); 143 } 144 else if (StringUtils.hasText(url.getQuery())) { 145 throw new MalformedURLException("query part should be empty."); 146 } 147 else if (StringUtils.hasText(url.getRef())) { 148 throw new MalformedURLException("ref part should be empty."); 149 } 150 else if (StringUtils.hasText(url.getUserInfo())) { 151 throw new MalformedURLException("user info part should be empty."); 152 } 153 urlHandlerImageSource.getImage(url.getPath()); 154 Resource image = urlHandlerImageSource.getImageResource(url.getPath()); 155 if (image != null) 156 return image.getURL().openConnection(); 157 158 throw new IOException("null image returned for key [" + url.getFile() + "]."); 159 } 160 }