Author: mircea.markus
Date: 2008-10-14 13:54:41 -0400 (Tue, 14 Oct 2008)
New Revision: 6949
Added:
core/branches/flat/src/main/java/org/jboss/cache/interceptors/MarshalledValueInterceptor.java
core/branches/flat/src/main/java/org/jboss/cache/marshall/MarshalledValueMap.java
Log:
Added:
core/branches/flat/src/main/java/org/jboss/cache/interceptors/MarshalledValueInterceptor.java
===================================================================
---
core/branches/flat/src/main/java/org/jboss/cache/interceptors/MarshalledValueInterceptor.java
(rev 0)
+++
core/branches/flat/src/main/java/org/jboss/cache/interceptors/MarshalledValueInterceptor.java 2008-10-14
17:54:41 UTC (rev 6949)
@@ -0,0 +1,210 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.cache.interceptors;
+
+import org.jboss.cache.InvocationContext;
+import org.jboss.cache.commands.ReplicableCommand;
+import org.jboss.cache.commands.read.GetChildrenNamesCommand;
+import org.jboss.cache.commands.read.GetDataMapCommand;
+import org.jboss.cache.commands.read.GetKeyValueCommand;
+import org.jboss.cache.commands.read.GetKeysCommand;
+import org.jboss.cache.commands.read.GetNodeCommand;
+import org.jboss.cache.commands.write.ClearDataCommand;
+import org.jboss.cache.commands.write.PutDataMapCommand;
+import org.jboss.cache.commands.write.PutForExternalReadCommand;
+import org.jboss.cache.commands.write.PutKeyValueCommand;
+import org.jboss.cache.commands.write.RemoveKeyCommand;
+import org.jboss.cache.interceptors.base.CommandInterceptor;
+import org.jboss.starobrno.marshall.MarshalledValue;
+import org.jboss.starobrno.marshall.MarshalledValueHelper;
+import org.jboss.cache.marshall.MarshalledValueMap;
+
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Interceptor that handles the wrapping and unwrapping of cached data using {@link
org.jboss.starobrno.marshall.MarshalledValue}s.
+ * Known "excluded" types are not wrapped/unwrapped, which at this time include
{@link String}, Java primitives
+ * and their Object wrappers, as well as arrays of excluded types.
+ * <p/>
+ * The {@link org.jboss.starobrno.marshall.MarshalledValue} wrapper handles lazy
deserialization from byte array representations.
+ *
+ * @author Manik Surtani (<a
href="mailto:manik@jboss.org">manik@jboss.org</a>)
+ * @see org.jboss.starobrno.marshall.MarshalledValue
+ * @since 2.1.0
+ */
+public class MarshalledValueInterceptor extends CommandInterceptor
+{
+
+ @Override
+ public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command)
throws Throwable
+ {
+ Set<MarshalledValue> marshalledValues = new
HashSet<MarshalledValue>();
+ command.setData(wrapMap(command.getData(), marshalledValues, ctx));
+ Object retVal = invokeNextInterceptor(ctx, command);
+ return compactAndProcessRetVal(command, marshalledValues, retVal);
+ }
+
+ @Override
+ public Object visitGetDataMapCommand(InvocationContext ctx, GetDataMapCommand command)
throws Throwable
+ {
+ Object retVal = invokeNextInterceptor(ctx, command);
+ if (retVal instanceof Map)
+ {
+ if (trace) log.trace("Return value is a Map and we're retrieving data.
Wrapping as a MarshalledValueMap.");
+ Map retValMap = (Map) retVal;
+ if (!retValMap.isEmpty()) retVal = new MarshalledValueMap(retValMap);
+ }
+ return retVal;
+ }
+
+ @Override
+ public Object visitPutForExternalReadCommand(InvocationContext ctx,
PutForExternalReadCommand command) throws Throwable
+ {
+ return visitPutKeyValueCommand(ctx, command);
+ }
+
+ @Override
+ public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand
command) throws Throwable
+ {
+ Set<MarshalledValue> marshalledValues = new
HashSet<MarshalledValue>();
+ if (!MarshalledValueHelper.isTypeExcluded(command.getKey().getClass()))
+ {
+ Object newKey = createAndAddMarshalledValue(command.getKey(), marshalledValues,
ctx);
+ command.setKey(newKey);
+ }
+ if (!MarshalledValueHelper.isTypeExcluded(command.getValue().getClass()))
+ {
+ Object value = createAndAddMarshalledValue(command.getValue(), marshalledValues,
ctx);
+ command.setValue(value);
+ }
+ Object retVal = invokeNextInterceptor(ctx, command);
+ return compactAndProcessRetVal(command, marshalledValues, retVal);
+ }
+
+ @Override
+ public Object visitGetNodeCommand(InvocationContext ctx, GetNodeCommand command)
throws Throwable
+ {
+ Object retVal = invokeNextInterceptor(ctx, command);
+ return processRetVal(retVal);
+ }
+
+ @Override
+ public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command)
throws Throwable
+ {
+ Object retVal = invokeNextInterceptor(ctx, command);
+ return processRetVal(retVal);
+ }
+
+ @Override
+ public Object visitRemoveKeyCommand(InvocationContext ctx, RemoveKeyCommand command)
throws Throwable
+ {
+ Set<MarshalledValue> marshalledValues = new
HashSet<MarshalledValue>();
+ if (!MarshalledValueHelper.isTypeExcluded(command.getKey().getClass()))
+ {
+ Object value = createAndAddMarshalledValue(command.getKey(), marshalledValues,
ctx);
+ command.setKey(value);
+ }
+ Object retVal = invokeNextInterceptor(ctx, command);
+ return compactAndProcessRetVal(command, marshalledValues, retVal);
+ }
+
+ @Override
+ public Object visitGetChildrenNamesCommand(InvocationContext ctx,
GetChildrenNamesCommand command) throws Throwable
+ {
+ Object retVal = invokeNextInterceptor(ctx, command);
+ return processRetVal(retVal);
+ }
+
+ @Override
+ public Object visitGetKeysCommand(InvocationContext ctx, GetKeysCommand command)
throws Throwable
+ {
+ Object retVal = invokeNextInterceptor(ctx, command);
+ return processRetVal(retVal);
+ }
+
+ @Override
+ public Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand
command) throws Throwable
+ {
+ Set<MarshalledValue> marshalledValues = new
HashSet<MarshalledValue>();
+ if (!MarshalledValueHelper.isTypeExcluded(command.getKey().getClass()))
+ {
+ Object value = createAndAddMarshalledValue(command.getKey(), marshalledValues,
ctx);
+ command.setKey(value);
+ }
+ Object retVal = invokeNextInterceptor(ctx, command);
+ return compactAndProcessRetVal(command, marshalledValues, retVal);
+ }
+
+ private Object compactAndProcessRetVal(ReplicableCommand command,
Set<MarshalledValue> marshalledValues, Object retVal)
+ throws IOException, ClassNotFoundException
+ {
+ if (trace) log.trace("Compacting MarshalledValues created");
+ for (MarshalledValue mv : marshalledValues) mv.compact(false, false);
+
+ return processRetVal(retVal);
+ }
+
+ private Object processRetVal(Object retVal)
+ throws IOException, ClassNotFoundException
+ {
+ if (retVal instanceof MarshalledValue)
+ {
+ if (trace) log.trace("Return value is a MarshalledValue.
Unwrapping.");
+ retVal = ((MarshalledValue) retVal).get();
+ }
+ return retVal;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Map wrapMap(Map<Object, Object> m, Set<MarshalledValue>
marshalledValues, InvocationContext ctx) throws NotSerializableException
+ {
+ if (m == null)
+ {
+ if (trace) log.trace("Map is nul; returning an empty map.");
+ return Collections.emptyMap();
+ }
+ if (trace) log.trace("Wrapping map contents of argument " + m);
+ Map copy = new HashMap();
+ for (Map.Entry me : m.entrySet())
+ {
+ Object key = me.getKey();
+ Object value = me.getValue();
+ copy.put((key == null || MarshalledValueHelper.isTypeExcluded(key.getClass())) ?
key : createAndAddMarshalledValue(key, marshalledValues, ctx),
+ (value == null || MarshalledValueHelper.isTypeExcluded(value.getClass()))
? value : createAndAddMarshalledValue(value, marshalledValues, ctx));
+ }
+ return copy;
+ }
+
+ protected MarshalledValue createAndAddMarshalledValue(Object toWrap,
Set<MarshalledValue> marshalledValues, InvocationContext ctx) throws
NotSerializableException
+ {
+ MarshalledValue mv = new MarshalledValue(toWrap);
+ marshalledValues.add(mv);
+ if (!ctx.isOriginLocal()) mv.setEqualityPreferenceForInstance(false);
+ return mv;
+ }
+}
Added: core/branches/flat/src/main/java/org/jboss/cache/marshall/MarshalledValueMap.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/cache/marshall/MarshalledValueMap.java
(rev 0)
+++
core/branches/flat/src/main/java/org/jboss/cache/marshall/MarshalledValueMap.java 2008-10-14
17:54:41 UTC (rev 6949)
@@ -0,0 +1,182 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.jboss.cache.marshall;
+
+import net.jcip.annotations.Immutable;
+import org.jboss.starobrno.CacheException;
+import org.jboss.starobrno.marshall.MarshalledValue;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A Map that is able to wrap/unwrap MarshalledValues in keys or values. Note that
calling keySet(), entrySet() or values()
+ * could be expensive if this map is large!!
+ * <p/>
+ * Also note that this is an immutable Map.
+ * <p/>
+ *
+ * @author Manik Surtani (<a
href="mailto:manik@jboss.org">manik@jboss.org</a>)
+ * @see org.jboss.starobrno.marshall.MarshalledValue
+ * @since 2.1.0
+ */
+@Immutable
+public class MarshalledValueMap implements Map, Externalizable
+{
+ Map delegate;
+ Map<Object, Object> unmarshalled;
+
+ public MarshalledValueMap()
+ {
+ // for externalization
+ }
+
+ public MarshalledValueMap(Map delegate)
+ {
+ this.delegate = delegate;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected synchronized Map getUnmarshalledMap()
+ {
+ if (unmarshalled == null) unmarshalled = unmarshalledMap(delegate.entrySet());
+ return unmarshalled;
+ }
+
+ public int size()
+ {
+ return delegate.size();
+ }
+
+ public boolean isEmpty()
+ {
+ return delegate.isEmpty();
+ }
+
+ public boolean containsKey(Object key)
+ {
+ return getUnmarshalledMap().containsKey(key);
+ }
+
+ public boolean containsValue(Object value)
+ {
+ return getUnmarshalledMap().containsValue(value);
+ }
+
+ public Object get(Object key)
+ {
+ return getUnmarshalledMap().get(key);
+ }
+
+ public Object put(Object key, Object value)
+ {
+ throw new UnsupportedOperationException("This is an immutable map!");
+ }
+
+ public Object remove(Object key)
+ {
+ throw new UnsupportedOperationException("This is an immutable map!");
+ }
+
+ public void putAll(Map t)
+ {
+ throw new UnsupportedOperationException("This is an immutable map!");
+ }
+
+ public void clear()
+ {
+ throw new UnsupportedOperationException("This is an immutable map!");
+ }
+
+ public Set keySet()
+ {
+ return getUnmarshalledMap().keySet();
+ }
+
+ public Collection values()
+ {
+ return getUnmarshalledMap().values();
+ }
+
+ public Set entrySet()
+ {
+ return getUnmarshalledMap().entrySet();
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Map unmarshalledMap(Set entries)
+ {
+ if (entries == null || entries.isEmpty()) return Collections.emptyMap();
+ Map map = new HashMap(entries.size());
+ for (Object e : entries)
+ {
+ Map.Entry entry = (Map.Entry) e;
+ map.put(getUnmarshalledValue(entry.getKey()),
getUnmarshalledValue(entry.getValue()));
+ }
+ return map;
+ }
+
+ private Object getUnmarshalledValue(Object o)
+ {
+ try
+ {
+ return o instanceof MarshalledValue ? ((MarshalledValue) o).get() : o;
+ }
+ catch (Exception e)
+ {
+ throw new CacheException("Unable to unmarshall value", e);
+ }
+ }
+
+ @Override
+ public boolean equals(Object other)
+ {
+ if (other instanceof Map)
+ {
+ return getUnmarshalledMap().equals(other);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return getUnmarshalledMap().hashCode();
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException
+ {
+ out.writeObject(delegate);
+ }
+
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+ {
+ delegate = (Map) in.readObject();
+ }
+}