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