/* * 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.geode.internal.cache.tier.sockets; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.Map; import java.util.Set; import org.apache.geode.DataSerializer; import org.apache.geode.internal.Version; import org.apache.geode.internal.cache.EnumListenerEvent; import org.apache.geode.internal.cache.EventID; import org.apache.geode.internal.cache.LocalRegion; import org.apache.geode.internal.cache.tier.Acceptor; import org.apache.geode.internal.cache.tier.MessageType; import org.apache.geode.internal.cache.versions.VersionSource; /** * * */ public class ClientTombstoneMessage extends ClientUpdateMessageImpl { enum TOperation { GC, GC_PR } private Object removalInformation; private TOperation op; /** GC operation for non-partitioned regions */ public static ClientTombstoneMessage gc(LocalRegion region, Map<VersionSource, Long> regionGCVersions, EventID eventId) { return new ClientTombstoneMessage(TOperation.GC, region, regionGCVersions, eventId); } /** GC operation for partitioned regions */ public static ClientTombstoneMessage gc(LocalRegion region, Set<Object> removedKeys, EventID eventId) { return new ClientTombstoneMessage(TOperation.GC_PR, region, removedKeys, eventId); } private ClientTombstoneMessage(TOperation op, LocalRegion region, Object removalInformation, EventID eventId) { super(EnumListenerEvent.AFTER_TOMBSTONE_EXPIRATION, null, eventId); this.op = op; this.removalInformation = removalInformation; setRegionName(region.getFullPath()); // fix for bug #45962 - tombstone message must have the // region name } /** * default constructor */ public ClientTombstoneMessage() {} @Override public boolean shouldBeConflated() { return false; } /* * Returns a <code>Message</code> generated from the fields of this * <code>ClientTombstoneMessage</code>. */ @Override protected Message getMessage(CacheClientProxy proxy, byte[] latestValue) throws IOException { if (Version.GFE_70.compareTo(proxy.getVersion()) <= 0) { return getGFE70Message(proxy.getVersion()); } else { return null; } } protected Message getGFE70Message(Version clientVersion) { Message message = null; // The format: // part 0: operation (gc=0) // part 1: region name // part 2: operation ordinal // part 3: regionGCVersions // Last part: event ID int numParts = 4; message = new Message(numParts, clientVersion); // Set message type message.setMessageType(MessageType.TOMBSTONE_OPERATION); message.addStringPart(this.getRegionName()); message.addIntPart(this.op.ordinal()); message.addObjPart(this.removalInformation); message.addObjPart(getEventId()); return message; } @Override public int getDSFID() { return CLIENT_TOMBSTONE_MESSAGE; } @Override public void toData(DataOutput out) throws IOException { out.writeByte(op.ordinal()); out.writeByte(_operation.getEventCode()); DataSerializer.writeString(getRegionName(), out); DataSerializer.writeObject(this.removalInformation, out); DataSerializer.writeObject(this._membershipId, out); DataSerializer.writeObject(this._eventIdentifier, out); } @Override public void fromData(DataInput in) throws IOException, ClassNotFoundException { // note: does not call super.fromData() since there are no keys, etc. // The message class hierarchy should be revised to have a more abstract // top-level class. this.op = TOperation.values()[in.readByte()]; this._operation = EnumListenerEvent.getEnumListenerEvent(in.readByte()); this.setRegionName(DataSerializer.readString(in)); this.removalInformation = DataSerializer.readObject(in); this._membershipId = ClientProxyMembershipID.readCanonicalized(in); this._eventIdentifier = (EventID) DataSerializer.readObject(in); } @Override public Object getKeyToConflate() { return null; } @Override public String getRegionToConflate() { return null; } @Override public Object getValueToConflate() { return null; } @Override public void setLatestValue(Object value) {} @Override public boolean isClientInterested(ClientProxyMembershipID clientId) { return Acceptor.VERSION.compareTo(Version.GFE_70) >= 0; } @Override public boolean needsNoAuthorizationCheck() { return true; } @Override public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("ClientTombstoneMessage[op=").append(this.op).append(";region=") .append(getRegionName()).append(";removalInfo=").append(this.removalInformation) .append(";memberId=").append(getMembershipId()).append(";eventId=").append(getEventId()) .append("]"); return buffer.toString(); } }