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.juneau.marshall.swaps;
018
019import static org.apache.juneau.commons.utils.IoUtils.*;
020import static org.apache.juneau.commons.utils.StringUtils.*;
021
022import java.io.*;
023
024import org.apache.juneau.marshall.*;
025import org.apache.juneau.marshall.swap.spi.*;
026
027/**
028 * Transforms <code>InputStreams</code> to {@link String Strings}.
029 *
030 * <h5 class='section'>See Also:</h5><ul>
031 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Swaps">Swap</a>
032
033 * </ul>
034 */
035@SuppressWarnings({
036   "resource" // unswap(...) returns a Closeable owned by the caller (the swap consumer); Eclipse JDT @Owning warning is by design.
037})
038public abstract class InputStreamSwap extends StringSwap<InputStream> {
039
040   /**
041    * Converts {@link InputStream InputStreams} to BASE-64 encoding.
042    */
043   public static class Base64 extends InputStreamSwap {
044
045      /**
046       * Converts the specified {@link InputStream} to a {@link String}.
047       */
048      @Override /* Overridden from ObjectSwap */
049      public String swap(MarshallingSession session, InputStream is) throws Exception {
050         return base64Encode(toBytes(is));
051      }
052
053      /**
054       * Converts the specified {@link String} to an {@link InputStream}.
055       */
056      @Override /* Overridden from ObjectSwap */
057      public InputStream unswap(MarshallingSession session, String s, ClassMeta<?> hint) throws Exception {
058         return toStream(base64Decode(s), hint);
059      }
060   }
061
062   /**
063    * Converts {@link InputStream InputStreams} to hex encoding.
064    */
065   public static class Hex extends InputStreamSwap {
066
067      /**
068       * Converts the specified {@link InputStream} to a {@link String}.
069       */
070      @Override /* Overridden from ObjectSwap */
071      public String swap(MarshallingSession session, InputStream is) throws Exception {
072         return toHex(toBytes(is));
073      }
074
075      /**
076       * Converts the specified {@link String} to an {@link InputStream}.
077       */
078      @Override /* Overridden from ObjectSwap */
079      public InputStream unswap(MarshallingSession session, String s, ClassMeta<?> hint) throws Exception {
080         return toStream(fromHex(s), hint);
081      }
082   }
083
084   /**
085    * Converts {@link InputStream InputStreams} to spaced-hex encoding.
086    */
087   public static class SpacedHex extends InputStreamSwap {
088
089      /**
090       * Converts the specified {@link InputStream} to a {@link String}.
091       */
092      @Override /* Overridden from ObjectSwap */
093      public String swap(MarshallingSession session, InputStream is) throws Exception {
094         return toSpacedHex(toBytes(is));
095      }
096
097      /**
098       * Converts the specified {@link String} to an {@link InputStream}.
099       */
100      @Override /* Overridden from ObjectSwap */
101      public InputStream unswap(MarshallingSession session, String s, ClassMeta<?> hint) throws Exception {
102         return toStream(fromSpacedHex(s), hint);
103      }
104   }
105
106   /**
107    * Convert the specified input stream to a byte array.
108    *
109    * @param is
110    *    The input stream to convert to bytes.
111    *    <br>Can be <jk>null</jk> (returns an empty array).
112    *    <br>The stream is automatically closed.
113    * @return The byte array.
114    * @throws IOException Thrown by input stream.
115    */
116   protected byte[] toBytes(InputStream is) throws IOException {
117      return readBytes(is);
118   }
119
120   /**
121    * Convert the specified byte array into an input stream.
122    *
123    * @param b The byte array.
124    * @param hint
125    *    Contains a hint about what subtype is being requested.
126    *    <br>Can be <jk>null</jk>, in which case {@link InputStream} is assumed.
127    * @return
128    *    The contents of the byte array as an input stream, or <jk>null</jk> if the hint requests a
129    *    stream subtype other than {@link InputStream} or {@link ByteArrayInputStream}.
130    */
131   protected InputStream toStream(byte[] b, ClassMeta<?> hint) {
132      var c = hint == null ? InputStream.class : hint.inner();
133      if (c == InputStream.class || c == ByteArrayInputStream.class)
134         return new ByteArrayInputStream(b);
135      return null;
136   }
137}