001package co.codewizards.cloudstore.core.dto.jaxb; 002 003import static co.codewizards.cloudstore.core.io.StreamUtil.*; 004import static java.util.Objects.*; 005 006import java.io.BufferedInputStream; 007import java.io.BufferedOutputStream; 008import java.io.IOException; 009import java.io.InputStream; 010import java.io.OutputStream; 011import java.lang.reflect.ParameterizedType; 012import java.lang.reflect.Type; 013import java.util.zip.GZIPInputStream; 014import java.util.zip.GZIPOutputStream; 015 016import javax.xml.bind.JAXBException; 017import javax.xml.bind.Marshaller; 018import javax.xml.bind.Unmarshaller; 019 020import co.codewizards.cloudstore.core.io.ByteArrayInputStream; 021import co.codewizards.cloudstore.core.io.ByteArrayOutputStream; 022import co.codewizards.cloudstore.core.io.NoCloseInputStream; 023import co.codewizards.cloudstore.core.io.NoCloseOutputStream; 024import co.codewizards.cloudstore.core.oio.File; 025 026public abstract class DtoIo <D> { 027 028 private final Class<D> dtoClass; 029 030 private Marshaller marshaller; 031 private Unmarshaller unmarshaller; 032 033 protected DtoIo() { 034 final ParameterizedType superclass = (ParameterizedType) getClass().getGenericSuperclass(); 035 final Type[] actualTypeArguments = superclass.getActualTypeArguments(); 036 if (actualTypeArguments == null || actualTypeArguments.length < 1) 037 throw new IllegalStateException("Subclass " + getClass().getName() + " has no generic type argument!"); 038 039 @SuppressWarnings("unchecked") 040 final Class<D> c = (Class<D>) actualTypeArguments[0]; 041 this.dtoClass = c; 042 if (this.dtoClass == null) 043 throw new IllegalStateException("Subclass " + getClass().getName() + " has no generic type argument!"); 044 } 045 046 public byte[] serialize(final D dto) { 047 final ByteArrayOutputStream out = new ByteArrayOutputStream(); 048 serialize(dto, out); 049 return out.toByteArray(); 050 } 051 052 public void serialize(final D dto, final OutputStream out) { 053 requireNonNull(dto, "dto"); 054 requireNonNull(out, "out"); 055 try { 056 getMarshaller().marshal(dto, new NoCloseOutputStream(out)); 057 } catch (final JAXBException e) { 058 throw new RuntimeException(e); 059 } 060 } 061 062 public byte[] serializeWithGz(final D dto) { 063 final ByteArrayOutputStream out = new ByteArrayOutputStream(); 064 serializeWithGz(dto, out); 065 return out.toByteArray(); 066 } 067 068 public void serializeWithGz(final D dto, final OutputStream out) { 069 requireNonNull(dto, "dto"); 070 requireNonNull(out, "out"); 071 try { 072 try (GZIPOutputStream gzOut = new GZIPOutputStream(new NoCloseOutputStream(out));) { 073 getMarshaller().marshal(dto, gzOut); 074 } 075 } catch (JAXBException | IOException e) { 076 throw new RuntimeException(e); 077 } 078 } 079 080 public void serialize(final D dto, final File file) { 081 requireNonNull(dto, "dto"); 082 requireNonNull(file, "file"); 083 try { 084 // Even though https://github.com/cloudstore/cloudstore/issues/31 seems to affect only unmarshal(File), 085 // we manage the OutputStream ourself, as well. 086 try (final OutputStream out = new BufferedOutputStream(castStream(file.createOutputStream()))) { 087 getMarshaller().marshal(dto, out); 088 } 089 } catch (JAXBException | IOException e) { 090 throw new RuntimeException("Writing file '" + file.getAbsolutePath() + "' failed: " + e, e); 091 } 092 } 093 094 public void serializeWithGz(final D dto, final File file) { 095 requireNonNull(dto, "dto"); 096 requireNonNull(file, "file"); 097 try { 098 // Even though https://github.com/cloudstore/cloudstore/issues/31 seems to affect only unmarshal(File), 099 // we manage the OutputStream ourself, as well. 100 try (final OutputStream out = new BufferedOutputStream(castStream(file.createOutputStream()))) { 101 try (GZIPOutputStream gzOut = new GZIPOutputStream(out);) { 102 getMarshaller().marshal(dto, gzOut); 103 } 104 } 105 } catch (JAXBException | IOException e) { 106 throw new RuntimeException("Writing file '" + file.getAbsolutePath() + "' failed: " + e, e); 107 } 108 } 109 110 public D deserialize(final byte[] in) { 111 requireNonNull(in, "in"); 112 return deserialize(new ByteArrayInputStream(in)); 113 } 114 115 public D deserialize(final InputStream in) { 116 requireNonNull(in, "in"); 117 try { 118 return dtoClass.cast(getUnmarshaller().unmarshal(new NoCloseInputStream(in))); 119 } catch (final JAXBException e) { 120 throw new RuntimeException(e); 121 } 122 } 123 124 public D deserializeWithGz(final byte[] in) { 125 requireNonNull(in, "in"); 126 return deserializeWithGz(new ByteArrayInputStream(in)); 127 } 128 129 public D deserializeWithGz(final InputStream in) { 130 requireNonNull(in, "in"); 131 try { 132 try (GZIPInputStream gzIn = new GZIPInputStream(new NoCloseInputStream(in));) { 133 return dtoClass.cast(getUnmarshaller().unmarshal(gzIn)); 134 } 135 } catch (JAXBException | IOException e) { 136 throw new RuntimeException(e); 137 } 138 } 139 140 public D deserialize(final File file) { 141 requireNonNull(file, "file"); 142 try { 143 // Because of https://github.com/cloudstore/cloudstore/issues/31 we do not use unmarshal(File), anymore. 144 try (final InputStream in = new BufferedInputStream(castStream(file.createInputStream()))) { 145 return dtoClass.cast(getUnmarshaller().unmarshal(in)); 146 } 147 } catch (JAXBException | IOException e) { 148 throw new RuntimeException("Reading file '" + file.getAbsolutePath() + "' failed: " + e, e); 149 } 150 } 151 152 public D deserializeWithGz(final File file) { 153 requireNonNull(file, "file"); 154 try { 155 // Because of https://github.com/cloudstore/cloudstore/issues/31 we do not use unmarshal(File), anymore. 156 try (final InputStream in = new BufferedInputStream(castStream(file.createInputStream()))) { 157 try (GZIPInputStream gzIn = new GZIPInputStream(in);) { 158 return dtoClass.cast(getUnmarshaller().unmarshal(gzIn)); 159 } 160 } 161 } catch (JAXBException | IOException e) { 162 throw new RuntimeException("Reading file '" + file.getAbsolutePath() + "' failed: " + e, e); 163 } 164 } 165 166 private Marshaller getMarshaller() { 167 if (marshaller == null) { 168 try { 169 marshaller = CloudStoreJaxbContext.getJaxbContext().createMarshaller(); 170 } catch (final JAXBException e) { 171 throw new RuntimeException(e); 172 } 173 } 174 return marshaller; 175 } 176 177 private Unmarshaller getUnmarshaller() { 178 if (unmarshaller == null) { 179 try { 180 unmarshaller = CloudStoreJaxbContext.getJaxbContext().createUnmarshaller(); 181 } catch (final JAXBException e) { 182 throw new RuntimeException(e); 183 } 184 } 185 return unmarshaller; 186 } 187}