| /* |
| * 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.sequencelog.io; |
| |
| import java.io.BufferedOutputStream; |
| import java.io.DataOutputStream; |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.util.HashMap; |
| import java.util.IdentityHashMap; |
| import java.util.regex.Pattern; |
| |
| import org.apache.geode.internal.sequencelog.Transition; |
| |
| /** |
| * Appends events logged using the SequenceLogger to a binary stream. |
| * |
| */ |
| public class OutputStreamAppender { |
| private IdentityHashMap<Object, Integer> writtenObjects = new IdentityHashMap<Object, Integer>(); |
| private HashMap<String, Integer> writtenStrings = new HashMap<String, Integer>(); |
| private DataOutputStream outputStream; |
| |
| private int nextInt = 0; |
| |
| public static final byte EDGE_RECORD = 0x01; |
| public static final byte STRING_RECORD = 0x02; |
| |
| public OutputStreamAppender(File file) throws FileNotFoundException { |
| this(new FileOutputStream(file)); |
| } |
| |
| public OutputStreamAppender(OutputStream out) throws FileNotFoundException { |
| this.outputStream = new DataOutputStream(new BufferedOutputStream(out, 256)); |
| writtenObjects.put(null, Integer.valueOf(-1)); |
| } |
| |
| public void write(Transition edge) throws IOException { |
| byte graphType = edge.getType().getId(); |
| // TODO - really we should deal with null and read it back in as null as well. |
| String stateName = edge.getState() == null ? "null" : edge.getState().toString(); |
| long timestamp = edge.getTimestamp(); |
| int edgeId = canonalize(edge.getEdgeName()); |
| int source = canonalize(edge.getSource()); |
| int dest = canonalize(edge.getDest()); |
| |
| outputStream.write(EDGE_RECORD); |
| outputStream.writeLong(timestamp); |
| outputStream.write(graphType); |
| writeGraphName(edge.getGraphName()); |
| outputStream.writeUTF(stateName); |
| outputStream.writeInt(edgeId); |
| outputStream.writeInt(source); |
| outputStream.writeInt(dest); |
| outputStream.flush(); |
| } |
| |
| private void writeGraphName(Object graphName) throws IOException { |
| boolean isPattern = graphName instanceof Pattern; |
| outputStream.writeBoolean(isPattern); |
| if (isPattern) { |
| final Pattern pattern = (Pattern) graphName; |
| outputStream.writeUTF(pattern.pattern()); |
| outputStream.writeInt(pattern.flags()); |
| } else { |
| outputStream.writeUTF(graphName.toString()); |
| } |
| } |
| |
| private int canonalize(Object object) throws IOException { |
| Integer id = writtenObjects.get(object); |
| if (id != null) { |
| return id.intValue(); |
| } |
| String toString = object.toString(); |
| id = writtenStrings.get(toString); |
| if (id != null) { |
| return id.intValue(); |
| } |
| |
| id = Integer.valueOf(nextInt++); |
| |
| outputStream.write(STRING_RECORD); |
| outputStream.writeUTF(toString); |
| |
| writtenObjects.put(object, id); |
| writtenStrings.put(toString, id); |
| return id.intValue(); |
| } |
| |
| public void close() { |
| try { |
| outputStream.close(); |
| } catch (IOException e) { |
| // do nothing |
| } |
| } |
| } |