001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.util.resource; 018 019import java.io.ByteArrayInputStream; 020import java.io.IOException; 021import java.io.InputStream; 022import java.io.InputStreamReader; 023import java.io.Reader; 024import java.io.UnsupportedEncodingException; 025import java.nio.charset.Charset; 026import java.time.Instant; 027import org.apache.wicket.util.io.IOUtils; 028import org.apache.wicket.util.io.Streams; 029import org.apache.wicket.util.lang.Bytes; 030import org.apache.wicket.util.string.Strings; 031 032 033/** 034 * Base class for string resources. 035 * 036 * @author Jonathan Locke 037 */ 038public abstract class AbstractStringResourceStream extends AbstractResourceStream 039 implements 040 IStringResourceStream 041{ 042 private static final long serialVersionUID = 1L; 043 044 /** The content-type applied in case the resource stream's default constructor is used */ 045 public static final String DEFAULT_CONTENT_TYPE = "text"; 046 047 /** Charset name for resource */ 048 private String charsetName; 049 050 /** MIME content type */ 051 private final String contentType; 052 053 /** The last time this stylesheet was modified */ 054 private Instant lastModified = null; 055 056 /** 057 * Constructor. 058 */ 059 public AbstractStringResourceStream() 060 { 061 this(DEFAULT_CONTENT_TYPE); 062 } 063 064 /** 065 * Constructor. 066 * 067 * @param contentType 068 * The mime type of this resource, such as "image/jpeg" or "text/html" 069 */ 070 public AbstractStringResourceStream(final String contentType) 071 { 072 // TODO null for contentType is allowed? or should the default be applied instead? 073 this.contentType = contentType; 074 075 lastModified = Instant.now(); 076 } 077 078 /** 079 * @return This resource as a String. 080 */ 081 @Override 082 public String asString() 083 { 084 Reader reader = null; 085 try 086 { 087 if (charsetName == null) 088 { 089 reader = new InputStreamReader(getInputStream()); 090 } 091 else 092 { 093 reader = new InputStreamReader(getInputStream(), getCharset()); 094 } 095 return Streams.readString(reader); 096 } 097 catch (IOException e) 098 { 099 throw new RuntimeException("Unable to read resource as String", e); 100 } 101 catch (ResourceStreamNotFoundException e) 102 { 103 throw new RuntimeException("Unable to read resource as String", e); 104 } 105 finally 106 { 107 IOUtils.closeQuietly(reader); 108 IOUtils.closeQuietly(this); 109 } 110 } 111 112 /** 113 * @return Charset for resource 114 */ 115 protected Charset getCharset() 116 { 117 // java.nio.Charset is not serializable so we can only store the name 118 return (charsetName != null) ? Charset.forName(charsetName) : null; 119 } 120 121 /** 122 * Sets the character set used for reading this resource. 123 * 124 * @param charset 125 * Charset for component 126 */ 127 @Override 128 public void setCharset(final Charset charset) 129 { 130 // java.nio.Charset itself is not serializable so we can only store the name 131 charsetName = (charset != null) ? charset.name() : null; 132 } 133 134 /** 135 * @see org.apache.wicket.util.resource.IResourceStream#close() 136 */ 137 @Override 138 public void close() throws IOException 139 { 140 } 141 142 /** 143 * @see org.apache.wicket.util.resource.IResourceStream#getContentType() 144 */ 145 @Override 146 public String getContentType() 147 { 148 return contentType; 149 } 150 151 /** 152 * @see org.apache.wicket.util.resource.IResourceStream#getInputStream() 153 */ 154 @Override 155 public InputStream getInputStream() throws ResourceStreamNotFoundException 156 { 157 final byte[] bytes; 158 if (getCharset() != null) 159 { 160 try 161 { 162 bytes = getString().getBytes(getCharset().name()); 163 } 164 catch (UnsupportedEncodingException e) 165 { 166 throw new ResourceStreamNotFoundException("Could not encode resource", e); 167 } 168 } 169 else 170 { 171 bytes = getString().getBytes(); 172 } 173 return new ByteArrayInputStream(bytes); 174 } 175 176 /** 177 * @see org.apache.wicket.util.watch.IModifiable#lastModifiedTime() 178 */ 179 @Override 180 public Instant lastModifiedTime() 181 { 182 return lastModified; 183 } 184 185 /** 186 * @param lastModified 187 * The lastModified to set. 188 */ 189 public void setLastModified(final Instant lastModified) 190 { 191 this.lastModified = lastModified; 192 } 193 194 /** 195 * @return The string resource 196 */ 197 protected abstract String getString(); 198 199 @Override 200 public final Bytes length() 201 { 202 int lengthInBytes = Strings.lengthInBytes(getString(), getCharset()); 203 return Bytes.bytes(lengthInBytes); 204 } 205}