mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2024-11-24 07:35:38 +01:00
Deleting java/common.
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@6 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
68b748fc58
commit
019890bab7
@ -1,47 +0,0 @@
|
|||||||
<project name="AirbagShared" default="compile" basedir=".">
|
|
||||||
<property name="src.home" value="${basedir}/src"/>
|
|
||||||
<property name="lib.home" value="${basedir}/../third-party"/>
|
|
||||||
<property name="dist.home" value="${basedir}/dist"/>
|
|
||||||
<property name="app.name" value="airbag-common"/>
|
|
||||||
<property name="doc.home" value="${basedir}/docs"/>
|
|
||||||
<property name="build.home" value="${basedir}/build"/>
|
|
||||||
|
|
||||||
<property name="compile.debug" value="true"/>
|
|
||||||
<property name="compile.deprecation" value="true"/>
|
|
||||||
<property name="compile.optimize" value="false"/>
|
|
||||||
|
|
||||||
<path id="compile.classpath">
|
|
||||||
<pathelement location="${lib.home}/servlet-api.jar"/>
|
|
||||||
</path>
|
|
||||||
|
|
||||||
<target name="compile"
|
|
||||||
description="Compile Java sources">
|
|
||||||
<mkdir dir="${build.home}"/>
|
|
||||||
<javac srcdir="${src.home}"
|
|
||||||
destdir="${build.home}"
|
|
||||||
debug="${compile.debug}"
|
|
||||||
deprecation="${compile.deprecation}"
|
|
||||||
optimize="${compile.optimize}">
|
|
||||||
<classpath refid="compile.classpath"/>
|
|
||||||
</javac>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<target name="javadoc" depends="compile"
|
|
||||||
description="Create Javadoc API documentation">
|
|
||||||
<mkdir dir="${dist.home}/docs"/>
|
|
||||||
<javadoc sourcepath="${src.home}"
|
|
||||||
destdir="${dist.home}/docs"
|
|
||||||
packagenames="*">
|
|
||||||
<classpath refid="compile.classpath"/>
|
|
||||||
</javadoc>
|
|
||||||
</target>
|
|
||||||
|
|
||||||
<target name="dist" depends="compile,javadoc"
|
|
||||||
description="Create binary distribution">
|
|
||||||
<mkdir dir="${dist.home}/docs"/>
|
|
||||||
|
|
||||||
<!-- Create JAR file -->
|
|
||||||
<jar jarfile="${dist.home}/${app.name}.jar"
|
|
||||||
basedir="${build.home}"/>
|
|
||||||
</target>
|
|
||||||
</project>
|
|
@ -1,135 +0,0 @@
|
|||||||
/* Copyright (C) 2006 Google 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 com.google.airbag.common;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.text.NumberFormat;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.SortedMap;
|
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServlet;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Common part of uploading a file with parameters. A subclass needs to
|
|
||||||
* provide a ReportStorage implementation.
|
|
||||||
*
|
|
||||||
* An upload file is saved in the file storage with parsed parameters from
|
|
||||||
* the URL.
|
|
||||||
*
|
|
||||||
* A separate processor will access the file storage and process these
|
|
||||||
* reports.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public class AbstractMinidumpServlet extends HttpServlet {
|
|
||||||
// Minidump storage to be instantiated by subclasses in init() method.
|
|
||||||
protected ReportStorage minidumpStorage;
|
|
||||||
|
|
||||||
// Random number generator
|
|
||||||
private final Random random = new Random();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Always return success to a GET, to keep out nosy people who go
|
|
||||||
* directly to the URL.
|
|
||||||
*/
|
|
||||||
public void doGet(HttpServletRequest req, HttpServletResponse res) {
|
|
||||||
res.setStatus(HttpServletResponse.SC_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes the file POSTed to the server and writes it to a file storage.
|
|
||||||
* Parameters in URL are saved as attributes of the file.
|
|
||||||
*
|
|
||||||
* @param req a wrapped HttpServletRequest that represents a multipart
|
|
||||||
* request
|
|
||||||
* @return unique ID for this report, can be used to get parameters and
|
|
||||||
* uploaded file contents from a file storage. If these is a
|
|
||||||
* collation, returns null.
|
|
||||||
*
|
|
||||||
* @throws ServletException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
protected String saveFile(MultipartRequest req)
|
|
||||||
throws ServletException, IOException {
|
|
||||||
// parse mutilpart request
|
|
||||||
SortedMap<String, String> params = req.getParameters();
|
|
||||||
|
|
||||||
//TODO(fqian): verify required fields of a report
|
|
||||||
InputStream inputs = req.getInputStream();
|
|
||||||
|
|
||||||
/* It is possible that two or more clients report crashes at the same
|
|
||||||
* time with same parameters. To reduce the chance of collation, we
|
|
||||||
* add two internal parameters:
|
|
||||||
* 1. reporting time, a time string in the form of YYMMDD-HHMMSS;
|
|
||||||
* 2. a random number;
|
|
||||||
*
|
|
||||||
* In theory, there is still a chance to collate, but it is very low.
|
|
||||||
* When collation happens, the one coming later is dropped.
|
|
||||||
*/
|
|
||||||
// 1. add a timestamp to parameters
|
|
||||||
params.put(NameConstants.REPORTTIME_PNAME, currentTimeString());
|
|
||||||
|
|
||||||
// 2. get a random number to make the change of collation very small
|
|
||||||
int r;
|
|
||||||
synchronized (this.random) {
|
|
||||||
r = this.random.nextInt();
|
|
||||||
}
|
|
||||||
params.put(NameConstants.RANDOMNUM_PNAME, Integer.toString(r));
|
|
||||||
|
|
||||||
String fid = this.minidumpStorage.getUniqueId(params);
|
|
||||||
|
|
||||||
assert fid != null;
|
|
||||||
|
|
||||||
if (this.minidumpStorage.reportExists(fid)) {
|
|
||||||
// collation happens
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.minidumpStorage.saveAttributes(fid, params);
|
|
||||||
// save uploaded contents to the storage
|
|
||||||
this.minidumpStorage.writeStreamToReport(fid, inputs, 0);
|
|
||||||
|
|
||||||
return fid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Gets a string representing the current time using the format:
|
|
||||||
* YYMMDD-HHMMSS.
|
|
||||||
*/
|
|
||||||
private String currentTimeString() {
|
|
||||||
NumberFormat formatter = NumberFormat.getInstance();
|
|
||||||
formatter.setGroupingUsed(false);
|
|
||||||
formatter.setMinimumIntegerDigits(2); // 2 digits per date component
|
|
||||||
|
|
||||||
// All servers are in Pacific time
|
|
||||||
Calendar cal = Calendar.getInstance();
|
|
||||||
|
|
||||||
StringBuffer tstring = new StringBuffer();
|
|
||||||
tstring.append(formatter.format(cal.get(Calendar.YEAR)));
|
|
||||||
// We want January = 1.
|
|
||||||
tstring.append(formatter.format((cal.get(Calendar.MONTH) + 1)));
|
|
||||||
tstring.append(formatter.format(cal.get(Calendar.DAY_OF_MONTH)));
|
|
||||||
tstring.append("-");
|
|
||||||
tstring.append(formatter.format(cal.get(Calendar.HOUR_OF_DAY)));
|
|
||||||
tstring.append(formatter.format(cal.get(Calendar.MINUTE)));
|
|
||||||
tstring.append(formatter.format(cal.get(Calendar.SECOND)));
|
|
||||||
|
|
||||||
return new String(tstring);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,188 +0,0 @@
|
|||||||
/* Copyright (C) 2006 Google 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 com.google.airbag.common;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.SortedMap;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
/** A utility class used by crash reporting server. */
|
|
||||||
|
|
||||||
public class CrashUtils {
|
|
||||||
// A map from numbers to hexadecimal characters.
|
|
||||||
private static final char[] maps = {
|
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
|
||||||
'A', 'B', 'C', 'D', 'E', 'F',
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final String MD_ALGORITHM = "MD5";
|
|
||||||
|
|
||||||
// delimiter between record
|
|
||||||
private static final String RECORD_DELIMITER = ";";
|
|
||||||
private static final String FIELD_DELIMITER = " ";
|
|
||||||
private static final int BUFFER_SIZE = 1024;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a byte array, returns a string of its hex representation.
|
|
||||||
* Each byte is represented by two characters for its high and low
|
|
||||||
* parts. For example, if the input is [0x3F, 0x01], this method
|
|
||||||
* returns 3F01.
|
|
||||||
*
|
|
||||||
* @param bs a byte array
|
|
||||||
* @return a string of hexadecimal characters
|
|
||||||
*/
|
|
||||||
public static String bytesToHexString(byte[] bs) {
|
|
||||||
StringBuffer sb = new StringBuffer();
|
|
||||||
for (byte b : bs) {
|
|
||||||
int high = (b >> 4) & 0x0F;
|
|
||||||
int low = b & 0x0F;
|
|
||||||
sb.append(maps[high]);
|
|
||||||
sb.append(maps[low]);
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a byte array, computes its message digest using one-way hash
|
|
||||||
* functions.
|
|
||||||
*
|
|
||||||
* @param data a byte array
|
|
||||||
* @return a string as its signature, or null if no message digest
|
|
||||||
* algorithm
|
|
||||||
* supported by the system.
|
|
||||||
*/
|
|
||||||
public static String dataSignature(byte[] data) {
|
|
||||||
try {
|
|
||||||
MessageDigest md = MessageDigest.getInstance(MD_ALGORITHM);
|
|
||||||
return bytesToHexString(md.digest(data));
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute the signature of a file by calling dataSignature on file
|
|
||||||
* contents.
|
|
||||||
*
|
|
||||||
* @param file a file name which signature to be computed
|
|
||||||
* @return the method signature of the file, or null if failed to
|
|
||||||
* read file contents, or message digest algorithm is not supported
|
|
||||||
*/
|
|
||||||
public static String fileSignature(File file) {
|
|
||||||
try {
|
|
||||||
FileInputStream fis = new FileInputStream(file);
|
|
||||||
byte[] buf = new byte[BUFFER_SIZE];
|
|
||||||
MessageDigest md = MessageDigest.getInstance(MD_ALGORITHM);
|
|
||||||
while (true) {
|
|
||||||
int bytesRead = fis.read(buf, 0, BUFFER_SIZE);
|
|
||||||
if (bytesRead == -1)
|
|
||||||
break;
|
|
||||||
md.update(buf, 0, bytesRead);
|
|
||||||
}
|
|
||||||
return bytesToHexString(md.digest());
|
|
||||||
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
return null;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes an attribute map to a string. Encoded string format:
|
|
||||||
* name value1[ value2];name value1[ value2]
|
|
||||||
* Names and values should be escaped so that there are no
|
|
||||||
* RECORD_DELIMITER and VALUE_DELIMITER in strings.
|
|
||||||
*
|
|
||||||
* @param attributes a maps of attributes name and value to be encoded
|
|
||||||
* @return a string of encoded attributes
|
|
||||||
*/
|
|
||||||
public static
|
|
||||||
String attributesToString(SortedMap<String, String> attributes) {
|
|
||||||
StringBuffer res = new StringBuffer();
|
|
||||||
for (Map.Entry<String, String> e : attributes.entrySet()) {
|
|
||||||
String name = e.getKey();
|
|
||||||
String value = e.getValue();
|
|
||||||
|
|
||||||
assert name.indexOf(RECORD_DELIMITER) == -1;
|
|
||||||
assert name.indexOf(FIELD_DELIMITER) == -1;
|
|
||||||
res.append(name).append(FIELD_DELIMITER);
|
|
||||||
|
|
||||||
assert value.indexOf(RECORD_DELIMITER) == -1;
|
|
||||||
assert value.indexOf(FIELD_DELIMITER) == -1;
|
|
||||||
res.append(value).append(RECORD_DELIMITER);
|
|
||||||
}
|
|
||||||
return new String(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes a string to a map of attributes.
|
|
||||||
*/
|
|
||||||
public static SortedMap<String, String> stringToAttributes(String s) {
|
|
||||||
SortedMap<String, String> map =
|
|
||||||
new TreeMap<String, String>();
|
|
||||||
String[] records = s.split(RECORD_DELIMITER);
|
|
||||||
for (String r : records) {
|
|
||||||
String[] fields = r.trim().split(FIELD_DELIMITER);
|
|
||||||
if (fields.length != 2) // discard records that has no values
|
|
||||||
continue;
|
|
||||||
String name = fields[0].trim();
|
|
||||||
String value = fields[1].trim();
|
|
||||||
map.put(name, value);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies bytes from an input stream to an output stream, with max bytes.
|
|
||||||
*
|
|
||||||
* @param ins an input stream to read
|
|
||||||
* @param outs an output stream to write
|
|
||||||
* @param max the maximum number of bytes to copy. If max <= 0, copy bytes
|
|
||||||
* until the end of input stream
|
|
||||||
* @return the number of bytes copied
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static int copyStream(InputStream ins, OutputStream outs, int max)
|
|
||||||
throws IOException {
|
|
||||||
byte[] buf = new byte[BUFFER_SIZE];
|
|
||||||
int bytesWritten = 0;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
int bytesToRead = BUFFER_SIZE;
|
|
||||||
if (max > 0)
|
|
||||||
bytesToRead = Math.min(BUFFER_SIZE, max - bytesWritten);
|
|
||||||
|
|
||||||
if (bytesToRead <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
int bytesRead = ins.read(buf, 0, bytesToRead);
|
|
||||||
if (bytesRead == -1) // end of input stream
|
|
||||||
break;
|
|
||||||
outs.write(buf, 0, bytesRead);
|
|
||||||
bytesWritten += bytesRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytesWritten;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
/* Copyright (C) 2006 Google 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 com.google.airbag.common;
|
|
||||||
|
|
||||||
import java.util.SortedMap;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A common interface for different multipart HttpServletRequest
|
|
||||||
* implementations. The interface is simple enough to be used by the
|
|
||||||
* upload server.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public interface MultipartRequest {
|
|
||||||
/**
|
|
||||||
* Returns a sorted map of name to values of an HTTP request.
|
|
||||||
*/
|
|
||||||
public SortedMap<String, String> getParameters();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an input stream of uploading file.
|
|
||||||
*/
|
|
||||||
public InputStream getInputStream();
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
/* Copyright (C) 2006 Google 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 com.google.airbag.common;
|
|
||||||
|
|
||||||
/** A class defines URL parameter names. */
|
|
||||||
|
|
||||||
public class NameConstants {
|
|
||||||
// URL parameter names
|
|
||||||
// product name
|
|
||||||
public static final String PRODUCT_PNAME = "prod";
|
|
||||||
// version
|
|
||||||
public static final String VERSION_PNAME = "ver";
|
|
||||||
// application or module
|
|
||||||
public static final String APPLICATION_PNAME = "app";
|
|
||||||
// platform, e.g., win32, linux, mac
|
|
||||||
public static final String PLATFORM_PNAME = "plat";
|
|
||||||
// report format, e.g., dump, xml
|
|
||||||
public static final String FORMAT_PNAME = "fmt";
|
|
||||||
// process uptime
|
|
||||||
public static final String PROCESSUPTIME_PNAME = "procup";
|
|
||||||
// cumulative process uptime
|
|
||||||
public static final String CUMULATIVEUPTIME_PNAME = "cumup";
|
|
||||||
// time when report is created
|
|
||||||
public static final String REPORTTIME_PNAME = "rept";
|
|
||||||
// a random number
|
|
||||||
public static final String RANDOMNUM_PNAME = "rand";
|
|
||||||
// report checksum
|
|
||||||
public static final String CHECKSUM_PNAME = "sum";
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
/* Copyright (C) 2006 Google 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 com.google.airbag.common;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A queue interface for unprocessed report ids. The interface is intended
|
|
||||||
* for inter-process usage. A report uploading server enqueues new report
|
|
||||||
* ids, and a processor dequeues ids.
|
|
||||||
*
|
|
||||||
* The interface is much simpler than <b>java.util.Queue</b>. An implementation
|
|
||||||
* should provide a persistent storage of queued ids even when a process
|
|
||||||
* is killed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public interface ReportQueue {
|
|
||||||
/**
|
|
||||||
* Enqueue a record id.
|
|
||||||
*
|
|
||||||
* @param rid
|
|
||||||
* @return true if success
|
|
||||||
*/
|
|
||||||
public boolean enqueue(String rid);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enqueue a list of ids
|
|
||||||
*
|
|
||||||
* @param ids
|
|
||||||
* @return true if success
|
|
||||||
*/
|
|
||||||
public boolean enqueue(LinkedList<String> ids);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a queue is empty
|
|
||||||
* @return true if the queue is empty
|
|
||||||
*/
|
|
||||||
public boolean empty();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes several ids from the queue. An implementation decides how
|
|
||||||
* many ids to be removed.
|
|
||||||
*
|
|
||||||
* @return a list of queue
|
|
||||||
*/
|
|
||||||
public LinkedList<String> dequeue();
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
/* Copyright (C) 2006 Google 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 com.google.airbag.common;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements ReportQueue using directories. Some restrictions:
|
|
||||||
* <ul>
|
|
||||||
* <li>Ids must be valid file names;</li>
|
|
||||||
* <li>Ids cannot be duplicated, a duplicated id is ignored;</li>
|
|
||||||
* <li>No guarantees on ordering, in other words, this is not really
|
|
||||||
* a queue (with FIFO order);</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class ReportQueueDirImpl implements ReportQueue {
|
|
||||||
// maximum number of ids returned by dequque method.
|
|
||||||
private static final int MAX_DEQUEUED_IDS = 100;
|
|
||||||
|
|
||||||
// the directory name for storing files
|
|
||||||
private String queueDir;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an instance of ReportQueueDirImpl with a directory name.
|
|
||||||
* @param dirname
|
|
||||||
*/
|
|
||||||
public ReportQueueDirImpl(String dirname)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
this.queueDir = dirname;
|
|
||||||
File q = new File(dirname);
|
|
||||||
if (!q.exists())
|
|
||||||
q.mkdirs();
|
|
||||||
|
|
||||||
if (!q.isDirectory())
|
|
||||||
throw new IOException("name "+dirname
|
|
||||||
+" exits already, but not a directory.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Enqueue a report id. */
|
|
||||||
public boolean enqueue(String rid) {
|
|
||||||
//lock on the directory
|
|
||||||
// add a file named by id
|
|
||||||
File f = new File(this.queueDir, rid);
|
|
||||||
try {
|
|
||||||
return f.createNewFile();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Enqueue a list of ids. */
|
|
||||||
public boolean enqueue(LinkedList<String> ids) {
|
|
||||||
//lock on the directory
|
|
||||||
// add a file named by id
|
|
||||||
for (String rid : ids) {
|
|
||||||
File f = new File(this.queueDir, rid);
|
|
||||||
try {
|
|
||||||
if (!f.createNewFile())
|
|
||||||
return false;
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Checks if the queue is empty. */
|
|
||||||
public boolean empty() {
|
|
||||||
File f = new File(this.queueDir);
|
|
||||||
String[] ids = f.list();
|
|
||||||
if (ids == null)
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return ids.length == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Remove ids from the queue. */
|
|
||||||
public LinkedList<String> dequeue() {
|
|
||||||
// lock on the directory
|
|
||||||
LinkedList<String> rids = new LinkedList<String>();
|
|
||||||
File d = new File(this.queueDir);
|
|
||||||
String[] ids = d.list();
|
|
||||||
if (ids == null)
|
|
||||||
return rids;
|
|
||||||
|
|
||||||
for (int i =0; i < Math.min(ids.length, MAX_DEQUEUED_IDS); i++) {
|
|
||||||
File f = new File(this.queueDir, ids[i]);
|
|
||||||
f.delete();
|
|
||||||
rids.add(ids[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rids;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,126 +0,0 @@
|
|||||||
/* Copyright (C) 2006 Google 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 com.google.airbag.common;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.nio.channels.FileChannel;
|
|
||||||
import java.nio.channels.FileLock;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of ReportQueue using a shared file. File accesses are
|
|
||||||
* protected by a file lock. When dequeue, all reports in the file were
|
|
||||||
* returned and the file is truncated to length zero.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class ReportQueueFileImpl implements ReportQueue {
|
|
||||||
private static final Logger logger =
|
|
||||||
Logger.getLogger(ReportQueueFileImpl.class.getName());
|
|
||||||
private String queueFile;
|
|
||||||
|
|
||||||
/** Given a file name, creates an instance of ReportQueueFileImpl. */
|
|
||||||
public ReportQueueFileImpl(String fname) {
|
|
||||||
this.queueFile = fname;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Enqueues a report id. */
|
|
||||||
public boolean enqueue(String rid) {
|
|
||||||
try {
|
|
||||||
RandomAccessFile raf = new RandomAccessFile(this.queueFile, "rw");
|
|
||||||
FileChannel fc = raf.getChannel();
|
|
||||||
// block thread until lock is obtained
|
|
||||||
FileLock lock = fc.lock();
|
|
||||||
raf.seek(raf.length());
|
|
||||||
raf.writeBytes(rid);
|
|
||||||
raf.writeByte('\n');
|
|
||||||
lock.release();
|
|
||||||
fc.close();
|
|
||||||
raf.close();
|
|
||||||
return true;
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
logger.severe("Cannot open file "+this.queueFile+" for write.");
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.severe("Cannot write to file "+this.queueFile);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Enqueues a list of report ids. */
|
|
||||||
public boolean enqueue(LinkedList<String> ids) {
|
|
||||||
try {
|
|
||||||
RandomAccessFile raf = new RandomAccessFile(this.queueFile, "rw");
|
|
||||||
FileChannel fc = raf.getChannel();
|
|
||||||
// block thread until lock is obtained
|
|
||||||
FileLock lock = fc.lock();
|
|
||||||
raf.seek(raf.length());
|
|
||||||
for (String rid : ids) {
|
|
||||||
raf.writeBytes(rid);
|
|
||||||
raf.writeByte('\n');
|
|
||||||
}
|
|
||||||
lock.release();
|
|
||||||
fc.close();
|
|
||||||
raf.close();
|
|
||||||
return true;
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
logger.severe("Cannot open file "+this.queueFile+" for write.");
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.severe("Cannot write to file "+this.queueFile);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean empty() {
|
|
||||||
// check the length of the file
|
|
||||||
File f = new File(this.queueFile);
|
|
||||||
return f.length() == 0L;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LinkedList<String> dequeue() {
|
|
||||||
LinkedList<String> ids = new LinkedList<String>();
|
|
||||||
|
|
||||||
try {
|
|
||||||
RandomAccessFile raf = new RandomAccessFile(this.queueFile, "rw");
|
|
||||||
FileChannel fc = raf.getChannel();
|
|
||||||
FileLock flock = fc.lock();
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
String s = raf.readLine();
|
|
||||||
if (s == null)
|
|
||||||
break;
|
|
||||||
s = s.trim();
|
|
||||||
if (s.equals(""))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ids.add(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
fc.truncate(0L);
|
|
||||||
|
|
||||||
// release the lock
|
|
||||||
flock.release();
|
|
||||||
fc.close();
|
|
||||||
raf.close();
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
logger.severe("Cannot open file "+this.queueFile+" for write.");
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.severe("Cannot write to file "+this.queueFile);
|
|
||||||
}
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
/* Copyright (C) 2006 Google 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 com.google.airbag.common;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A test class for ReportQueue implementations, currently tests
|
|
||||||
* ReportQueueDirImpl and ReportQueueFileImpl.
|
|
||||||
*/
|
|
||||||
public class ReportQueueTest {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
ReportQueue rq = new ReportQueueFileImpl("/tmp/rqtest");
|
|
||||||
runTest(rq);
|
|
||||||
|
|
||||||
try {
|
|
||||||
rq = new ReportQueueDirImpl("/tmp/rqdir");
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
runTest(rq);
|
|
||||||
|
|
||||||
System.out.println("OK");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void runTest(ReportQueue rq) {
|
|
||||||
rq.enqueue("hello");
|
|
||||||
rq.enqueue("world");
|
|
||||||
|
|
||||||
LinkedList<String> v = rq.dequeue();
|
|
||||||
assert v.size() == 2;
|
|
||||||
|
|
||||||
assert v.get(0).equals("hello");
|
|
||||||
assert v.get(1).equals("world");
|
|
||||||
assert rq.empty();
|
|
||||||
|
|
||||||
v.remove();
|
|
||||||
|
|
||||||
rq.enqueue(v);
|
|
||||||
assert !rq.empty();
|
|
||||||
|
|
||||||
v = rq.dequeue();
|
|
||||||
assert v.size() == 1;
|
|
||||||
assert v.get(0).equals("world");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,134 +0,0 @@
|
|||||||
/* Copyright (C) 2006 Google 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 com.google.airbag.common;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
|
|
||||||
import java.util.SortedMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ReportStorage.java
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Provide an abstract layer for storing crash reports and associated meta
|
|
||||||
* data.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* The interface is intended to be used by a client in the following way:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* ReportStorage rs = new ReportStorageImpl(...);
|
|
||||||
* // Write an uploading file to a storage
|
|
||||||
* try {
|
|
||||||
* String rid = rs.getUniqueId(attributes); // params from URL
|
|
||||||
* rs.saveAttributes(id, attributes);
|
|
||||||
* if (!rs.reportExists(rid) || allowOverwrite)
|
|
||||||
* rs.writeStreamToReport(rid, input, 0);
|
|
||||||
* else
|
|
||||||
* rs.appendStreamToReport(rid, input, 0);
|
|
||||||
* } catch (...)
|
|
||||||
*
|
|
||||||
* // Read a file from the storage
|
|
||||||
* try {
|
|
||||||
* OutputStream os = fs.openReportForRead(fid);
|
|
||||||
* os.read(...);
|
|
||||||
* os.close();
|
|
||||||
* } catch (...)
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
|
|
||||||
public interface ReportStorage {
|
|
||||||
/**
|
|
||||||
* Given a sorted map of attributes (name and value), returns a unique id
|
|
||||||
* of the crash report.
|
|
||||||
*
|
|
||||||
* @param params a sorted map from name to value
|
|
||||||
* @return a string as the file id
|
|
||||||
*/
|
|
||||||
public String getUniqueId(SortedMap<String, String> params);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a report id, checks if the report data AND attributes identified
|
|
||||||
* by this id exists on the storage.
|
|
||||||
*
|
|
||||||
* @param id a report id
|
|
||||||
* @return true if the id represents an existing file
|
|
||||||
*/
|
|
||||||
public boolean reportExists(String id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a report id and a sorted map of attributes, saves attributes on
|
|
||||||
* the storage.
|
|
||||||
*
|
|
||||||
* @param id a report id
|
|
||||||
* @param attrs attributes associated with this id
|
|
||||||
* @return true if attributes are saved successfully
|
|
||||||
*/
|
|
||||||
public boolean saveAttributes(String id, SortedMap<String, String> attrs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a report id, returns attributes associated with this report.
|
|
||||||
*
|
|
||||||
* @param id a report id
|
|
||||||
* @return a sorted map from name to value
|
|
||||||
* @throws FileNotFoundException if fileExists(id) returns false
|
|
||||||
*/
|
|
||||||
public SortedMap<String, String> getAttributes(String id)
|
|
||||||
throws FileNotFoundException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes <i>max</i> bytes from an input stream to a report identified by
|
|
||||||
* an <i>id</i>.
|
|
||||||
*
|
|
||||||
* @param id a report id
|
|
||||||
* @param input an input stream
|
|
||||||
* @param max
|
|
||||||
* maximum bytes to be written, if max is less or equal than 0, it will
|
|
||||||
* write all bytes from input stream to the file
|
|
||||||
* @return the number of bytes written
|
|
||||||
* @throws FileNotFoundException
|
|
||||||
* if reportExists(id) returns false
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public int writeStreamToReport(String id, InputStream input, int max)
|
|
||||||
throws FileNotFoundException, IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a report for read.
|
|
||||||
*
|
|
||||||
* @param id a report id
|
|
||||||
* @return an output stream for read
|
|
||||||
* @throws FileNotFoundException
|
|
||||||
*/
|
|
||||||
public InputStream openReportForRead(String id) throws FileNotFoundException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param id a report id
|
|
||||||
* @return the checksum of a report.
|
|
||||||
* @throws FileNotFoundException
|
|
||||||
*/
|
|
||||||
public String getChecksum(String id) throws FileNotFoundException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes a report.
|
|
||||||
*
|
|
||||||
* @param id a report id
|
|
||||||
* @return true if the report is removed successfully
|
|
||||||
*/
|
|
||||||
public boolean removeReport(String id) throws FileNotFoundException;
|
|
||||||
}
|
|
@ -1,197 +0,0 @@
|
|||||||
/* Copyright (C) 2006 Google 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 com.google.airbag.common;
|
|
||||||
|
|
||||||
import java.util.SortedMap;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Implement FileStorage using a local file system.</p>
|
|
||||||
*
|
|
||||||
* <p>Given a sorted map of attributes, create a checksum as unique file
|
|
||||||
* id.</p>
|
|
||||||
*
|
|
||||||
* <p>Each file id is associated with two files in the storage:
|
|
||||||
* <ol>
|
|
||||||
* <li>an attribute file named as <id>.attr;</li>
|
|
||||||
* <li>a data file named as <id>.data;</li>
|
|
||||||
* </ol>
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class ReportStorageLocalFileImpl implements ReportStorage {
|
|
||||||
|
|
||||||
// Name extension of attribute file
|
|
||||||
private static final String ATTR_FILE_EXT = ".attr";
|
|
||||||
|
|
||||||
// Name extension of data file
|
|
||||||
private static final String DATA_FILE_EXT = ".data";
|
|
||||||
|
|
||||||
// Set the maximum file length at 1M
|
|
||||||
private static final long MAX_ATTR_FILE_LENGTH = 1 << 10;
|
|
||||||
|
|
||||||
// Logging
|
|
||||||
private static final Logger logger =
|
|
||||||
Logger.getLogger(ReportStorageLocalFileImpl.class.getName());
|
|
||||||
|
|
||||||
// Directory name for storing files.
|
|
||||||
private String directoryName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an instance of ReportStorageLocalFileImpl by providing a
|
|
||||||
* directory name.
|
|
||||||
*
|
|
||||||
* @param dirname a directory for storing files
|
|
||||||
* @throws IOException
|
|
||||||
* @throws NullPointerException if dirname is null
|
|
||||||
*/
|
|
||||||
public ReportStorageLocalFileImpl(String dirname) throws IOException {
|
|
||||||
this.directoryName = dirname;
|
|
||||||
// new File can throw NullPointerException if dirname is null
|
|
||||||
File dir = new File(dirname);
|
|
||||||
if (!dir.exists() && !dir.mkdirs())
|
|
||||||
throw new IOException("Cannot make dirs for "+dirname);
|
|
||||||
|
|
||||||
if (!dir.canWrite())
|
|
||||||
throw new IOException("Cannot write to "+dirname
|
|
||||||
+", check your permissions.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a hashed string of attributes. Attributes are saved
|
|
||||||
* in the file storage if not exists.
|
|
||||||
*/
|
|
||||||
public String getUniqueId(SortedMap<String, String> attributes)
|
|
||||||
{
|
|
||||||
String attr = CrashUtils.attributesToString(attributes);
|
|
||||||
return CrashUtils.dataSignature(attr.getBytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves attributes associated with a given id. if attributes does not
|
|
||||||
* match the id (comparing results of getUniqueId(attributes)
|
|
||||||
* with id), it returns false. Otherwise, attributes are saved.
|
|
||||||
*/
|
|
||||||
public boolean saveAttributes(String id, SortedMap<String, String> attributes)
|
|
||||||
{
|
|
||||||
String attr = CrashUtils.attributesToString(attributes);
|
|
||||||
String digest = CrashUtils.dataSignature(attr.getBytes());
|
|
||||||
|
|
||||||
if (!digest.equals(id))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
File attrFile = new File(this.directoryName, digest+ATTR_FILE_EXT);
|
|
||||||
|
|
||||||
// check if attr file exists
|
|
||||||
if (!attrFile.exists()) {
|
|
||||||
FileOutputStream fos = new FileOutputStream(attrFile);
|
|
||||||
fos.write(attr.getBytes());
|
|
||||||
fos.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
logger.warning(e.toString());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Checks if a report id exists. */
|
|
||||||
public boolean reportExists(String id) {
|
|
||||||
File datafile = new File(this.directoryName, id+DATA_FILE_EXT);
|
|
||||||
File attrfile = new File(this.directoryName, id+ATTR_FILE_EXT);
|
|
||||||
return datafile.isFile() && attrfile.isFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns attributes in a map associated with an id. */
|
|
||||||
public SortedMap<String, String> getAttributes(String id)
|
|
||||||
throws FileNotFoundException
|
|
||||||
{
|
|
||||||
if (!this.reportExists(id))
|
|
||||||
throw new FileNotFoundException("no file is identified by "+id);
|
|
||||||
|
|
||||||
File attrfile = new File(this.directoryName, id+ATTR_FILE_EXT);
|
|
||||||
if (!attrfile.isFile())
|
|
||||||
throw new FileNotFoundException("no file is identified by "+id);
|
|
||||||
|
|
||||||
int length = (int) attrfile.length();
|
|
||||||
if (length >= MAX_ATTR_FILE_LENGTH)
|
|
||||||
throw new FileNotFoundException("no file is identified by "+id);
|
|
||||||
|
|
||||||
byte[] content = new byte[length];
|
|
||||||
|
|
||||||
try {
|
|
||||||
FileInputStream fis = new FileInputStream(attrfile);
|
|
||||||
fis.read(content);
|
|
||||||
fis.close();
|
|
||||||
|
|
||||||
// verify checksum
|
|
||||||
String sig = CrashUtils.dataSignature(content);
|
|
||||||
if (!sig.equals(id)) {
|
|
||||||
logger.warning("illegal access to "+attrfile);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse contents
|
|
||||||
return CrashUtils.stringToAttributes(new String(content));
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.warning(e.toString());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int writeStreamToReport(String id, InputStream input, int max)
|
|
||||||
throws FileNotFoundException, IOException {
|
|
||||||
File datafile = new File(this.directoryName, id + DATA_FILE_EXT);
|
|
||||||
FileOutputStream fos = new FileOutputStream(datafile);
|
|
||||||
|
|
||||||
int bytesCopied = CrashUtils.copyStream(input, fos, max);
|
|
||||||
|
|
||||||
fos.close();
|
|
||||||
|
|
||||||
return bytesCopied;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream openReportForRead(String id) throws FileNotFoundException {
|
|
||||||
File datafile = new File(this.directoryName, id + DATA_FILE_EXT);
|
|
||||||
return new FileInputStream(datafile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getChecksum(String id) throws FileNotFoundException {
|
|
||||||
File datafile = new File(this.directoryName, id + DATA_FILE_EXT);
|
|
||||||
return CrashUtils.fileSignature(datafile);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean removeReport(String id) {
|
|
||||||
File datafile = new File(this.directoryName, id + DATA_FILE_EXT);
|
|
||||||
File attrfile = new File(this.directoryName, id + ATTR_FILE_EXT);
|
|
||||||
|
|
||||||
datafile.delete();
|
|
||||||
attrfile.delete();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
/* Copyright (C) 2006 Google 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 com.google.airbag.common;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
/** A simple regression test of ReportStorage.java and implementations.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class ReportStorageTest {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
// use /tmp/test as testing directory
|
|
||||||
ReportStorage rs = null;
|
|
||||||
try {
|
|
||||||
rs = new ReportStorageLocalFileImpl("/tmp/test");
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
runTest(rs);
|
|
||||||
|
|
||||||
// test passed
|
|
||||||
System.out.println("OK.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void runTest(ReportStorage rs) {
|
|
||||||
// test CrashUtil.bytesToHexString
|
|
||||||
byte[] ba = new byte[4];
|
|
||||||
ba[0] = (byte)0xFF;
|
|
||||||
ba[1] = (byte)0x00;
|
|
||||||
ba[2] = (byte)0x0F;
|
|
||||||
ba[3] = (byte)0xF0;
|
|
||||||
String s = CrashUtils.bytesToHexString(ba);
|
|
||||||
assert s.equals("FF000FF0");
|
|
||||||
|
|
||||||
// construct a simple map of attributes
|
|
||||||
TreeMap<String, String> params =
|
|
||||||
new TreeMap<String, String>();
|
|
||||||
params.put("Hello", "World");
|
|
||||||
String rid = rs.getUniqueId(params);
|
|
||||||
assert rid != null;
|
|
||||||
|
|
||||||
boolean b = rs.saveAttributes(rid, params);
|
|
||||||
assert b;
|
|
||||||
ba = "hellow, world!".getBytes();
|
|
||||||
InputStream in = new ByteArrayInputStream(ba);
|
|
||||||
|
|
||||||
assert rs.reportExists(rid);
|
|
||||||
|
|
||||||
// save contents to storage
|
|
||||||
try {
|
|
||||||
rs.writeStreamToReport(rid, in, 0);
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(1);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// read contents out
|
|
||||||
try {
|
|
||||||
InputStream in1 = rs.openReportForRead(rid);
|
|
||||||
assert in1.available() == ba.length;
|
|
||||||
in1.read(ba);
|
|
||||||
assert(new String(ba).equals("hellow, world!"));
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
/* Copyright (C) 2006 Google 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 com.google.airbag.common;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.SortedMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>SymbolStorage provides a simple interface for storing and retrieving
|
|
||||||
* symbol files. Symbol files are indexed by a set of attributes:
|
|
||||||
* <ul>
|
|
||||||
* <li>product name</li>
|
|
||||||
* <li>version (build id)</li>
|
|
||||||
* <li>platform</li>
|
|
||||||
* <li>application/module name</li>
|
|
||||||
* </ul>
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* The interface is designed for a symbol server supports upload, getid,
|
|
||||||
* download operations.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
|
|
||||||
public interface SymbolStorage {
|
|
||||||
/**
|
|
||||||
* Saves a symbol file indexed by a set of attributes. Attributes include
|
|
||||||
* product, version, platform, application/module, plus a checksum of
|
|
||||||
* the symbol file.
|
|
||||||
*
|
|
||||||
* If a symbol file whose checksum matches the attribute, the input stream
|
|
||||||
* can be NULL. No contents will be written. This can save some workloads
|
|
||||||
* of uploading symbols.
|
|
||||||
*
|
|
||||||
* @param attrs a map of attributes, it must have 'prod', 'ver', 'plat',
|
|
||||||
* 'app', and 'sum', values of the first four attributes are used
|
|
||||||
* as index, and the value of the last attribute is the MD5 checksum
|
|
||||||
* of the symbol file for verification.
|
|
||||||
* @param contents symbol file contents.
|
|
||||||
* @return true if checksum matches
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public boolean saveSymbolFile(SortedMap<String, String> attrs,
|
|
||||||
InputStream contents) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the checksum of a symbol file indexed by a set of attributes.
|
|
||||||
* @param attrs a map of attributes, must include 'prod', 'ver', 'plat',
|
|
||||||
* and 'app'.
|
|
||||||
* @return MD5 checksum as a string
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public String getFileChecksum(SortedMap<String, String> attrs)
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a file exists already (identified by its checksum).
|
|
||||||
* @param checksum the file checksum
|
|
||||||
* @return true if a file with the same checksum exists
|
|
||||||
*/
|
|
||||||
public boolean fileExists(String checksum);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an input stream of a symbol server indexed by a set of attributes.
|
|
||||||
* @param attrs a map of attributes, must include 'prod', 'ver', 'plat',
|
|
||||||
* and 'app'.
|
|
||||||
* @return an input stream of the symbol file
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public InputStream openFileForRead(SortedMap<String, String> attrs)
|
|
||||||
throws IOException;
|
|
||||||
}
|
|
@ -1,203 +0,0 @@
|
|||||||
/* Copyright (C) 2006 Google 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 com.google.airbag.common;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.SortedMap;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of SymbolStorage interface using a local file system.
|
|
||||||
*
|
|
||||||
* Given a set of parameters, prod, ver, app, plat, computes its MD5 digest.
|
|
||||||
* Digest + .attr contains attributes and checksum of the symbol file.
|
|
||||||
* Symbol file content is stored in a file named by its checksum + .data.
|
|
||||||
*
|
|
||||||
* To upload a symbol file, a client can send a query:
|
|
||||||
* <pre>
|
|
||||||
* /symexists?sum=<checksum>, the server checks if a symbol file identified by checksum exists;
|
|
||||||
* /upload?prod=<product>&ver=<version>&plat=<platform>&app=<module>&sum=<checksum> use POST
|
|
||||||
* method with or without uploading a file.
|
|
||||||
*
|
|
||||||
* A client can always call /upload to upload a symbol file.
|
|
||||||
* However, a more efficient way is to check whether a file is on the server by calling /symexists.
|
|
||||||
* If so, the client can just POST the request without actually upload the file content,
|
|
||||||
* checksum is sufficient.
|
|
||||||
*
|
|
||||||
* /getchecksum?prod=<product>&ver=<version>&plat=<platform>&app=<module>, returns the checksum
|
|
||||||
* of the symbol file on the server.
|
|
||||||
* /download?prod=<product>&ver=<version>&plat=<platform>&app=<module>, downloads the symbol file
|
|
||||||
* on the server.
|
|
||||||
*
|
|
||||||
* A client can always use /download to download a symbol file.
|
|
||||||
* However, if the client maintins its own cache of symbol files, it can call /getchecksum,
|
|
||||||
* and look up the cache using the checksum. If the cache does not have the file, then it
|
|
||||||
* calls /download.
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class SymbolStorageLocalFileImpl implements SymbolStorage {
|
|
||||||
|
|
||||||
// Name extension of attribute file
|
|
||||||
private static final String ATTR_FILE_EXT = ".attr";
|
|
||||||
|
|
||||||
// Name extension of data file
|
|
||||||
private static final String DATA_FILE_EXT = ".data";
|
|
||||||
|
|
||||||
private static final int MAX_ATTR_FILE_LENGTH = 1 << 10;
|
|
||||||
|
|
||||||
// Directory name for storing files.
|
|
||||||
private String directoryName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an instance of ReportStorageLocalFileImpl by providing a
|
|
||||||
* directory name.
|
|
||||||
*
|
|
||||||
* @param dirname
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public SymbolStorageLocalFileImpl(String dirname) throws IOException {
|
|
||||||
this.directoryName = dirname;
|
|
||||||
// new File can throw NullPointerException if dirname is null
|
|
||||||
File dir = new File(dirname);
|
|
||||||
if (!dir.exists() && !dir.mkdirs())
|
|
||||||
throw new IOException("Cannot make dirs for "+dirname);
|
|
||||||
|
|
||||||
if (!dir.canWrite())
|
|
||||||
throw new IOException("Cannot write to "+dirname
|
|
||||||
+", check your permissions.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save a symbol file.
|
|
||||||
*/
|
|
||||||
public boolean saveSymbolFile(SortedMap<String, String> attrs, InputStream contents)
|
|
||||||
throws IOException {
|
|
||||||
String digest = getAttributesSignature(attrs);
|
|
||||||
|
|
||||||
// get 'sum' value
|
|
||||||
String checksum = attrs.get(NameConstants.CHECKSUM_PNAME);
|
|
||||||
if (checksum == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// attribute file name and data file name
|
|
||||||
File attrFile = new File(this.directoryName, digest+ATTR_FILE_EXT);
|
|
||||||
|
|
||||||
// use passed in checksum as file name
|
|
||||||
File dataFile = new File(this.directoryName, checksum+DATA_FILE_EXT);
|
|
||||||
|
|
||||||
// write data to file
|
|
||||||
FileOutputStream outs = new FileOutputStream(dataFile);
|
|
||||||
CrashUtils.copyStream(contents, outs, 0);
|
|
||||||
outs.close();
|
|
||||||
|
|
||||||
// get signature of input stream
|
|
||||||
String filesig = CrashUtils.fileSignature(dataFile);
|
|
||||||
|
|
||||||
if (!checksum.equals(filesig)) {
|
|
||||||
dataFile.delete();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// save all attributes with checksum
|
|
||||||
String fullAttrs = CrashUtils.attributesToString(attrs);
|
|
||||||
|
|
||||||
FileOutputStream fos = new FileOutputStream(attrFile);
|
|
||||||
fos.write(fullAttrs.getBytes());
|
|
||||||
fos.close();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getFileChecksum(SortedMap<String, String> attrs) throws IOException {
|
|
||||||
String digest = getAttributesSignature(attrs);
|
|
||||||
File attrFile = new File(this.directoryName, digest+ATTR_FILE_EXT);
|
|
||||||
|
|
||||||
if (!attrFile.isFile())
|
|
||||||
throw new FileNotFoundException();
|
|
||||||
|
|
||||||
int length = (int) attrFile.length();
|
|
||||||
if (length >= MAX_ATTR_FILE_LENGTH)
|
|
||||||
throw new FileNotFoundException();
|
|
||||||
|
|
||||||
byte[] content = new byte[length];
|
|
||||||
|
|
||||||
FileInputStream fis = new FileInputStream(attrFile);
|
|
||||||
fis.read(content);
|
|
||||||
fis.close();
|
|
||||||
|
|
||||||
// parse contents
|
|
||||||
SortedMap<String, String> savedAttrs =
|
|
||||||
CrashUtils.stringToAttributes(new String(content));
|
|
||||||
|
|
||||||
return savedAttrs.get(NameConstants.CHECKSUM_PNAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean fileExists(String checksum) {
|
|
||||||
File dataFile = new File(this.directoryName, checksum+DATA_FILE_EXT);
|
|
||||||
return dataFile.isFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream openFileForRead(SortedMap<String, String> attrs)
|
|
||||||
throws IOException {
|
|
||||||
String checksum = getFileChecksum(attrs);
|
|
||||||
if (checksum == null)
|
|
||||||
throw new FileNotFoundException();
|
|
||||||
|
|
||||||
File dataFile = new File(this.directoryName, checksum + DATA_FILE_EXT);
|
|
||||||
if (!dataFile.isFile())
|
|
||||||
throw new FileNotFoundException();
|
|
||||||
|
|
||||||
return new FileInputStream(dataFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String[] requiredParameters = {
|
|
||||||
NameConstants.PRODUCT_PNAME,
|
|
||||||
NameConstants.APPLICATION_PNAME,
|
|
||||||
NameConstants.PLATFORM_PNAME,
|
|
||||||
NameConstants.VERSION_PNAME
|
|
||||||
};
|
|
||||||
|
|
||||||
private String getAttributesSignature(SortedMap<String, String> attrs) {
|
|
||||||
// canonize parameters
|
|
||||||
SortedMap<String, String> params = canonizeAttributes(attrs);
|
|
||||||
String attrString = CrashUtils.attributesToString(params);
|
|
||||||
return CrashUtils.dataSignature(attrString.getBytes());
|
|
||||||
}
|
|
||||||
/* Canonize attributes, get 'prod', 'ver', 'plat', and 'app' values,
|
|
||||||
* and put them in a new sorted map. If one of value is missing,
|
|
||||||
* returns null.
|
|
||||||
*/
|
|
||||||
private SortedMap<String, String>
|
|
||||||
canonizeAttributes(SortedMap<String, String> attrs) {
|
|
||||||
SortedMap<String, String> params = new TreeMap<String, String>();
|
|
||||||
for (String s : requiredParameters) {
|
|
||||||
String v = attrs.get(s);
|
|
||||||
if (v == null)
|
|
||||||
return null;
|
|
||||||
else
|
|
||||||
params.put(s, v);
|
|
||||||
}
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
/* Copyright (C) 2006 Google 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 com.google.airbag.common;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test ReportStorage and its implementation by simulating two pocesses
|
|
||||||
* as producer and consuer.
|
|
||||||
*
|
|
||||||
* To use this test with TestReportStorageProducer:
|
|
||||||
* > java TestReportStorageProducer /tmp/testdir
|
|
||||||
*
|
|
||||||
* In another console,
|
|
||||||
* > java TestReportStorageConsumer /tmp/testdir
|
|
||||||
*
|
|
||||||
* Then watch output on both console.
|
|
||||||
*/
|
|
||||||
public class TestReportStorageConsumer {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param args
|
|
||||||
*/
|
|
||||||
public static void main(String[] args) {
|
|
||||||
String testdir = args[0];
|
|
||||||
ReportStorage rs = null;
|
|
||||||
try {
|
|
||||||
rs = new ReportStorageLocalFileImpl(testdir);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
consume(rs);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void consume(ReportStorage rs) {
|
|
||||||
int i = 0;
|
|
||||||
TreeMap<String, String> params =
|
|
||||||
new TreeMap<String, String>();
|
|
||||||
String v = "hello";
|
|
||||||
byte[] buf = new byte[1024];
|
|
||||||
while (true) {
|
|
||||||
params.put(Integer.toString(i), v);
|
|
||||||
String id = rs.getUniqueId(params);
|
|
||||||
rs.saveAttributes(id, params);
|
|
||||||
if (rs.reportExists(id)) {
|
|
||||||
InputStream is = null;
|
|
||||||
try {
|
|
||||||
is = rs.openReportForRead(id);
|
|
||||||
while (is.read(buf) != -1) {
|
|
||||||
System.out.print(new String(buf));
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
break;
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
try {
|
|
||||||
Thread.sleep(1000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
/* Copyright (C) 2006 Google 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 com.google.airbag.common;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test ReportStorage and its implementation by simulating two pocesses
|
|
||||||
* as producer and consuer.
|
|
||||||
*
|
|
||||||
* To use this test with TestReportStorageConsumer:
|
|
||||||
* > java TestReportStorageProducer /tmp/testdir
|
|
||||||
*
|
|
||||||
* In another console,
|
|
||||||
* > java TestReportStorageConsumer /tmp/testdir
|
|
||||||
*
|
|
||||||
* Then watch output on both console.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class TestReportStorageProducer {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param args
|
|
||||||
*/
|
|
||||||
public static void main(String[] args) {
|
|
||||||
String testdir = args[0];
|
|
||||||
ReportStorage rs = null;
|
|
||||||
try {
|
|
||||||
rs = new ReportStorageLocalFileImpl(testdir);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
produce(rs);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void produce(ReportStorage rs) {
|
|
||||||
int i = 0;
|
|
||||||
TreeMap<String, String> params =
|
|
||||||
new TreeMap<String, String>();
|
|
||||||
String v = "hello";
|
|
||||||
ByteArrayInputStream ba = new ByteArrayInputStream("hello world!".getBytes());
|
|
||||||
while (true) {
|
|
||||||
ba.reset();
|
|
||||||
params.put(Integer.toString(i), v);
|
|
||||||
String id = rs.getUniqueId(params);
|
|
||||||
rs.saveAttributes(id, params);
|
|
||||||
if (id == null) {
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
rs.writeStreamToReport(id, ba, 0);
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
break;
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
try {
|
|
||||||
Thread.sleep(1000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user