/** * Copyright 2011-2013 Terracotta, Inc. * Copyright 2011-2013 Oracle, Inc. * * Licensed 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.jsr107.tck.integration; import org.jsr107.tck.support.OperationHandler; import org.jsr107.tck.support.Server; import javax.cache.Cache; import javax.cache.integration.CacheWriter; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Collection; import java.util.HashSet; /** * A {@link Server} that handles {@link CacheWriter} requests from a * {@link CacheWriterClient} and delegates them to an underlying {@link CacheWriter}. * * @param <K> the type of keys * @param <V> the type of values * @author Brian Oliver * @author Joe Fialli */ public class CacheWriterServer<K, V> extends Server { /** * The underlying {@link CacheWriter} that will be used to * load entries requested by the {@link CacheWriterClient}s. */ private CacheWriter<K, V> cacheWriter; /** * Constructs an CacheWriterServer. * * @param port the port on which to accept {@link CacheWriterClient} requests * @param cacheWriter (optional) the {@link CacheWriter} that will be used to handle * client requests */ public CacheWriterServer(int port, CacheWriter<K, V> cacheWriter) { super(port); // establish the client-server operation handlers addOperationHandler(new WriteOperationHandler()); addOperationHandler(new WriteAllOperationHandler()); addOperationHandler(new DeleteOperationHandler()); addOperationHandler(new DeleteAllOperationHandler()); this.cacheWriter = cacheWriter; } /** * Set the {@link CacheWriter} the {@link CacheWriterServer} should use * from now on. * * @param cacheWriter the {@link CacheWriter} */ public void setCacheWriter(CacheWriter<K, V> cacheWriter) { this.cacheWriter = cacheWriter; } public CacheWriter<K, V> getCacheWriter() { return cacheWriter; } /** * The {@link OperationHandler} for a {@link CacheWriter#deleteAll(java.util.Collection)}} operation. */ public class DeleteAllOperationHandler implements OperationHandler { @Override public String getType() { return "deleteAll"; } @Override public void onProcess(ObjectInputStream ois, ObjectOutputStream oos) throws IOException, ClassNotFoundException { if (cacheWriter == null) { throw new NullPointerException("The cacheWriter for the CacheWriterServer has not be set"); } else { HashSet<K> keys = new HashSet<>(); K key = (K) ois.readObject(); while (key != null) { keys.add(key); key = (K) ois.readObject(); } try { cacheWriter.deleteAll(keys); } catch (Exception e) { oos.writeObject(e); oos.writeObject(keys); return; } oos.writeObject(keys); } } } /** * The {@link OperationHandler} for a {@link CacheWriter#delete(Object)} operation. */ public class DeleteOperationHandler implements OperationHandler { /** * {@inheritDoc} */ @Override public String getType() { return "delete"; } /** * {@inheritDoc} */ @Override public void onProcess(ObjectInputStream ois, ObjectOutputStream oos) throws IOException, ClassNotFoundException { if (cacheWriter == null) { throw new NullPointerException("The cacheWriter for the CacheWriterServer has not be set"); } else { K key = (K) ois.readObject(); try { cacheWriter.delete(key); } catch (Exception e) { oos.writeObject(e); return; } // successful completion without an exception. oos.writeObject(null); } } } /** * An implementation of Cache.Entry. * @param <K> * @param <V> */ private static class Entry<K, V> implements Cache.Entry<K, V> { private final K key; private final V value; public Entry(K key, V value) { this.key = key; this.value = value; } @Override public K getKey() { return key; } @Override public V getValue() { return value; } @Override public <T> T unwrap(Class<T> clazz) { throw new UnsupportedOperationException("not implemented"); } } /** * The {@link OperationHandler} for a {@link CacheWriter#writeAll(java.util.Collection)}} operation. */ public class WriteAllOperationHandler implements OperationHandler { @Override public String getType() { return "writeAll"; } private Collection<Cache.Entry<? extends K, ? extends V>> readEntries(ObjectInputStream ois) throws IOException, ClassNotFoundException { Collection<Cache.Entry<? extends K, ? extends V>> entrys = new HashSet<Cache.Entry<? extends K, ? extends V>>(); K key = (K) ois.readObject(); V value = null; if (key != null) { value = (V) ois.readObject(); } Entry entry = ((key == null) || (value == null)) ? null : new Entry(key, value); while (entry != null) { entrys.add(entry); key = (K) ois.readObject(); value = null; if (key != null) { value = (V) ois.readObject(); } entry = ((key == null) || (value == null)) ? null : new Entry(key, value); } return entrys; } @Override public void onProcess(ObjectInputStream ois, ObjectOutputStream oos) throws IOException, ClassNotFoundException { if (cacheWriter == null) { throw new NullPointerException("The cacheWriter for the CacheWriterServer has not be set"); } else { Collection<Cache.Entry<? extends K, ? extends V>> entrys = readEntries(ois); try { cacheWriter.writeAll(entrys); } catch (Exception e) { oos.writeObject(e); for (Cache.Entry<? extends K, ? extends V> entry1 : entrys) { oos.writeObject(entry1.getKey()); } oos.writeObject(null); return; } assert(entrys.size() == 0); oos.writeObject(null); } } } /** * The {@link OperationHandler} for a {@link CacheWriter#write(javax.cache.Cache.Entry)} operation. */ public class WriteOperationHandler implements OperationHandler { /** * {@inheritDoc} */ @Override public String getType() { return "write"; } /** * {@inheritDoc} */ @Override public void onProcess(ObjectInputStream ois, ObjectOutputStream oos) throws IOException, ClassNotFoundException { if (cacheWriter == null) { throw new NullPointerException("The cacheWriter for the CacheWriterServer has not be set"); } else { final K key = (K) ois.readObject(); final V value = (V) ois.readObject(); Cache.Entry<K, V> entry = new Entry<>(key, value); try { if ((key != null) && (value != null)) { cacheWriter.write(entry); } } catch (Exception e) { oos.writeObject(e); return; } // successfully completed operation. oos.writeObject(null); } } } }