| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.ignite.internal.client.marshaller.optimized; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.nio.ByteBuffer; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.zip.ZipEntry; |
| import java.util.zip.ZipInputStream; |
| import java.util.zip.ZipOutputStream; |
| import org.apache.ignite.IgniteCheckedException; |
| import org.apache.ignite.internal.client.marshaller.GridClientMarshaller; |
| import org.apache.ignite.internal.marshaller.optimized.OptimizedMarshaller; |
| import org.apache.ignite.internal.processors.rest.client.message.GridClientMessage; |
| import org.apache.ignite.internal.util.typedef.internal.U; |
| import org.apache.ignite.plugin.PluginProvider; |
| import org.jetbrains.annotations.Nullable; |
| |
| /** |
| * Wrapper, that adapts {@link OptimizedMarshaller} to {@link GridClientMarshaller} interface. |
| */ |
| public class GridClientZipOptimizedMarshaller extends GridClientOptimizedMarshaller { |
| /** ID. */ |
| public static final byte ID = 3; |
| |
| /** Default buffer size. */ |
| private static final int DFLT_BUFFER_SIZE = 4096; |
| |
| /** Default client marshaller to fallback. */ |
| private final GridClientMarshaller dfltMarsh; |
| |
| /** |
| * Constructor. |
| * |
| * @param dfltMarsh Marshaller to fallback to. |
| * @param plugins Plugins. |
| */ |
| public GridClientZipOptimizedMarshaller(GridClientMarshaller dfltMarsh, @Nullable List<PluginProvider> plugins) { |
| super(plugins); |
| |
| assert dfltMarsh != null; |
| |
| this.dfltMarsh = dfltMarsh; |
| } |
| |
| /** |
| * Default marshaller that will be used in case of backward compatibility. |
| * |
| * @return Marshaller to fallback. |
| */ |
| public GridClientMarshaller defaultMarshaller() { |
| return dfltMarsh; |
| } |
| |
| /** |
| * Zips bytes. |
| * |
| * @param input Input bytes. |
| * @return Zipped byte array. |
| * @throws IOException If failed. |
| */ |
| public static byte[] zipBytes(byte[] input) throws IOException { |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(DFLT_BUFFER_SIZE); |
| |
| try (ZipOutputStream zos = new ZipOutputStream(baos)) { |
| ZipEntry entry = new ZipEntry(""); |
| |
| try { |
| entry.setSize(input.length); |
| |
| zos.putNextEntry(entry); |
| zos.write(input); |
| } |
| finally { |
| zos.closeEntry(); |
| } |
| } |
| |
| return baos.toByteArray(); |
| } |
| |
| /** |
| * Unzip bytes. |
| * |
| * @param input Zipped bytes. |
| * @return Unzipped byte array. |
| * @throws IOException |
| */ |
| private static byte[] unzipBytes(byte[] input) throws IOException { |
| ByteArrayInputStream bais = new ByteArrayInputStream(input); |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(DFLT_BUFFER_SIZE); |
| |
| try (ZipInputStream zis = new ZipInputStream(bais)) { |
| zis.getNextEntry(); |
| |
| byte[] buf = new byte[DFLT_BUFFER_SIZE]; |
| |
| int len = zis.read(buf); |
| |
| while (len > 0) { |
| baos.write(buf, 0, len); |
| |
| len = zis.read(buf); |
| } |
| } |
| |
| return baos.toByteArray(); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override public ByteBuffer marshal(Object obj, int off) throws IOException { |
| try { |
| if (!(obj instanceof GridClientMessage)) |
| throw new IOException("Message serialization of given type is not supported: " + |
| obj.getClass().getName()); |
| |
| byte[] marshBytes = U.marshal(opMarsh, obj); |
| |
| boolean zip = marshBytes.length > 512; |
| |
| byte[] bytes = zip ? zipBytes(marshBytes) : marshBytes; |
| |
| ByteBuffer buf = ByteBuffer.allocate(off + bytes.length + 1); |
| |
| buf.position(off); |
| buf.put((byte)(zip ? 1 : 0)); |
| buf.put(bytes); |
| buf.flip(); |
| |
| return buf; |
| } |
| catch (IgniteCheckedException e) { |
| throw new IOException(e); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| @Override public <T> T unmarshal(byte[] bytes) throws IOException { |
| try { |
| boolean unzip = bytes[0] > 0; |
| |
| byte[] marshBytes = Arrays.copyOfRange(bytes, 1, bytes.length); |
| |
| return U.unmarshal(opMarsh, unzip ? unzipBytes(marshBytes) : marshBytes, null); |
| } |
| catch (IgniteCheckedException e) { |
| throw new IOException(e); |
| } |
| } |
| } |