|
1 /** |
|
2 * Copyright (c) 2012, Ben Fortuna |
|
3 * All rights reserved. |
|
4 * |
|
5 * Redistribution and use in source and binary forms, with or without |
|
6 * modification, are permitted provided that the following conditions |
|
7 * are met: |
|
8 * |
|
9 * o Redistributions of source code must retain the above copyright |
|
10 * notice, this list of conditions and the following disclaimer. |
|
11 * |
|
12 * o Redistributions in binary form must reproduce the above copyright |
|
13 * notice, this list of conditions and the following disclaimer in the |
|
14 * documentation and/or other materials provided with the distribution. |
|
15 * |
|
16 * o Neither the name of Ben Fortuna nor the names of any other contributors |
|
17 * may be used to endorse or promote products derived from this software |
|
18 * without specific prior written permission. |
|
19 * |
|
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
|
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
|
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
31 */ |
|
32 package net.fortuna.ical4j.model.property; |
|
33 |
|
34 import java.io.IOException; |
|
35 import java.io.UnsupportedEncodingException; |
|
36 import java.net.URI; |
|
37 import java.net.URISyntaxException; |
|
38 |
|
39 import net.fortuna.ical4j.model.Parameter; |
|
40 import net.fortuna.ical4j.model.ParameterList; |
|
41 import net.fortuna.ical4j.model.Property; |
|
42 import net.fortuna.ical4j.model.PropertyFactoryImpl; |
|
43 import net.fortuna.ical4j.model.ValidationException; |
|
44 import net.fortuna.ical4j.model.parameter.Encoding; |
|
45 import net.fortuna.ical4j.model.parameter.Value; |
|
46 import net.fortuna.ical4j.util.DecoderFactory; |
|
47 import net.fortuna.ical4j.util.EncoderFactory; |
|
48 import net.fortuna.ical4j.util.ParameterValidator; |
|
49 import net.fortuna.ical4j.util.Strings; |
|
50 import net.fortuna.ical4j.util.Uris; |
|
51 |
|
52 import org.apache.commons.codec.BinaryDecoder; |
|
53 import org.apache.commons.codec.BinaryEncoder; |
|
54 import org.apache.commons.codec.DecoderException; |
|
55 import org.apache.commons.codec.EncoderException; |
|
56 import org.apache.commons.logging.Log; |
|
57 import org.apache.commons.logging.LogFactory; |
|
58 |
|
59 /** |
|
60 * $Id$ |
|
61 * |
|
62 * Created: [Apr 6, 2004] |
|
63 * |
|
64 * Defines an ATTACH iCalendar component property. |
|
65 * |
|
66 * <pre> |
|
67 * 4.8.1.1 Attachment |
|
68 * |
|
69 * Property Name: ATTACH |
|
70 * |
|
71 * Purpose: The property provides the capability to associate a document |
|
72 * object with a calendar component. |
|
73 * |
|
74 * Value Type: The default value type for this property is URI. The |
|
75 * value type can also be set to BINARY to indicate inline binary |
|
76 * encoded content information. |
|
77 * |
|
78 * Property Parameters: Non-standard, inline encoding, format type and |
|
79 * value data type property parameters can be specified on this |
|
80 * property. |
|
81 * |
|
82 * Conformance: The property can be specified in a "VEVENT", "VTODO", |
|
83 * "VJOURNAL" or "VALARM" calendar components. |
|
84 * |
|
85 * Description: The property can be specified within "VEVENT", "VTODO", |
|
86 * "VJOURNAL", or "VALARM" calendar components. This property can be |
|
87 * specified multiple times within an iCalendar object. |
|
88 * |
|
89 * Format Definition: The property is defined by the following notation: |
|
90 * |
|
91 * attach = "ATTACH" attparam ":" uri CRLF |
|
92 * |
|
93 * attach =/ "ATTACH" attparam ";" "ENCODING" "=" "BASE64" |
|
94 * ";" "VALUE" "=" "BINARY" ":" binary |
|
95 * |
|
96 * attparam = *( |
|
97 * |
|
98 * ; the following is optional, |
|
99 * ; but MUST NOT occur more than once |
|
100 * |
|
101 * (";" fmttypeparam) / |
|
102 * |
|
103 * ; the following is optional, |
|
104 * ; and MAY occur more than once |
|
105 * |
|
106 * (";" xparam) |
|
107 * |
|
108 * ) |
|
109 * </pre> |
|
110 * |
|
111 * @author benf |
|
112 */ |
|
113 public class Attach extends Property { |
|
114 |
|
115 private static final long serialVersionUID = 4439949507756383452L; |
|
116 |
|
117 private URI uri; |
|
118 |
|
119 private byte[] binary; |
|
120 |
|
121 /** |
|
122 * Default constructor. |
|
123 */ |
|
124 public Attach() { |
|
125 super(ATTACH, PropertyFactoryImpl.getInstance()); |
|
126 } |
|
127 |
|
128 /** |
|
129 * @param aList a list of parameters for this component |
|
130 * @param aValue a value string for this component |
|
131 * @throws IOException when there is an error reading the binary stream |
|
132 * @throws URISyntaxException where the specified string is not a valid uri |
|
133 */ |
|
134 public Attach(final ParameterList aList, final String aValue) |
|
135 throws IOException, URISyntaxException { |
|
136 super(ATTACH, aList, PropertyFactoryImpl.getInstance()); |
|
137 setValue(aValue); |
|
138 } |
|
139 |
|
140 /** |
|
141 * @param data binary data |
|
142 */ |
|
143 public Attach(final byte[] data) { |
|
144 super(ATTACH, PropertyFactoryImpl.getInstance()); |
|
145 // add required parameters.. |
|
146 getParameters().add(Encoding.BASE64); |
|
147 getParameters().add(Value.BINARY); |
|
148 this.binary = data; |
|
149 } |
|
150 |
|
151 /** |
|
152 * @param aList a list of parameters for this component |
|
153 * @param data binary data |
|
154 */ |
|
155 public Attach(final ParameterList aList, final byte[] data) { |
|
156 super(ATTACH, aList, PropertyFactoryImpl.getInstance()); |
|
157 this.binary = data; |
|
158 } |
|
159 |
|
160 /** |
|
161 * @param aUri a URI |
|
162 */ |
|
163 public Attach(final URI aUri) { |
|
164 super(ATTACH, PropertyFactoryImpl.getInstance()); |
|
165 this.uri = aUri; |
|
166 } |
|
167 |
|
168 /** |
|
169 * @param aList a list of parameters for this component |
|
170 * @param aUri a URI |
|
171 */ |
|
172 public Attach(final ParameterList aList, final URI aUri) { |
|
173 super(ATTACH, aList, PropertyFactoryImpl.getInstance()); |
|
174 this.uri = aUri; |
|
175 } |
|
176 |
|
177 /** |
|
178 * {@inheritDoc} |
|
179 */ |
|
180 public final void validate() throws ValidationException { |
|
181 |
|
182 /* |
|
183 * ; the following is optional, ; but MUST NOT occur more than once (";" fmttypeparam) / |
|
184 */ |
|
185 ParameterValidator.getInstance().assertOneOrLess(Parameter.FMTTYPE, |
|
186 getParameters()); |
|
187 |
|
188 /* |
|
189 * ; the following is optional, ; and MAY occur more than once (";" xparam) |
|
190 */ |
|
191 |
|
192 /* |
|
193 * If the value type parameter is ";VALUE=BINARY", then the inline encoding parameter MUST be specified with the |
|
194 * value ";ENCODING=BASE64". |
|
195 */ |
|
196 if (Value.BINARY.equals(getParameter(Parameter.VALUE))) { |
|
197 ParameterValidator.getInstance().assertOne(Parameter.ENCODING, |
|
198 getParameters()); |
|
199 if (!Encoding.BASE64.equals(getParameter(Parameter.ENCODING))) { |
|
200 throw new ValidationException( |
|
201 "If the value type parameter is [BINARY], the inline" |
|
202 + "encoding parameter MUST be specified with the value [BASE64]"); |
|
203 } |
|
204 } |
|
205 } |
|
206 |
|
207 /** |
|
208 * @return Returns the binary. |
|
209 */ |
|
210 public final byte[] getBinary() { |
|
211 return binary; |
|
212 } |
|
213 |
|
214 /** |
|
215 * @return Returns the uri. |
|
216 */ |
|
217 public final URI getUri() { |
|
218 return uri; |
|
219 } |
|
220 |
|
221 /** |
|
222 * Sets the current value of the Attach instance. If the specified |
|
223 * value is encoded binary data, the value is decoded and stored in |
|
224 * the binary field. Otherwise the value is assumed to be a URI |
|
225 * location to binary data and is stored as such. |
|
226 * |
|
227 * @param aValue a string encoded binary or URI value |
|
228 * @throws IOException where binary data cannot be decoded |
|
229 * @throws URISyntaxException where the specified value is not a valid URI |
|
230 */ |
|
231 public final void setValue(final String aValue) throws IOException, |
|
232 URISyntaxException { |
|
233 |
|
234 // determine if ATTACH is a URI or an embedded |
|
235 // binary.. |
|
236 if (getParameter(Parameter.ENCODING) != null) { |
|
237 // binary = Base64.decode(aValue); |
|
238 try { |
|
239 final BinaryDecoder decoder = DecoderFactory.getInstance() |
|
240 .createBinaryDecoder( |
|
241 (Encoding) getParameter(Parameter.ENCODING)); |
|
242 binary = decoder.decode(aValue.getBytes()); |
|
243 } |
|
244 catch (UnsupportedEncodingException uee) { |
|
245 Log log = LogFactory.getLog(Attach.class); |
|
246 log.error("Error encoding binary data", uee); |
|
247 } |
|
248 catch (DecoderException de) { |
|
249 Log log = LogFactory.getLog(Attach.class); |
|
250 log.error("Error decoding binary data", de); |
|
251 } |
|
252 } |
|
253 // assume URI.. |
|
254 else { |
|
255 uri = Uris.create(aValue); |
|
256 } |
|
257 } |
|
258 |
|
259 /** |
|
260 * {@inheritDoc} |
|
261 */ |
|
262 public final String getValue() { |
|
263 if (getUri() != null) { |
|
264 return Uris.decode(Strings.valueOf(getUri())); |
|
265 } |
|
266 else if (getBinary() != null) { |
|
267 // return Base64.encodeBytes(getBinary(), Base64.DONT_BREAK_LINES); |
|
268 try { |
|
269 final BinaryEncoder encoder = EncoderFactory.getInstance() |
|
270 .createBinaryEncoder( |
|
271 (Encoding) getParameter(Parameter.ENCODING)); |
|
272 return new String(encoder.encode(getBinary())); |
|
273 } |
|
274 catch (UnsupportedEncodingException uee) { |
|
275 Log log = LogFactory.getLog(Attach.class); |
|
276 log.error("Error encoding binary data", uee); |
|
277 } |
|
278 catch (EncoderException ee) { |
|
279 Log log = LogFactory.getLog(Attach.class); |
|
280 log.error("Error encoding binary data", ee); |
|
281 } |
|
282 } |
|
283 return null; |
|
284 } |
|
285 |
|
286 /** |
|
287 * @param binary The binary to set. |
|
288 */ |
|
289 public final void setBinary(final byte[] binary) { |
|
290 this.binary = binary; |
|
291 // unset uri.. |
|
292 this.uri = null; |
|
293 } |
|
294 |
|
295 /** |
|
296 * @param uri The uri to set. |
|
297 */ |
|
298 public final void setUri(final URI uri) { |
|
299 this.uri = uri; |
|
300 // unset binary.. |
|
301 this.binary = null; |
|
302 } |
|
303 } |