зеркало из https://github.com/mozilla/gecko-dev.git
vivat grendel!
This commit is contained in:
Родитель
12d97f5341
Коммит
a7d6d7afa6
|
@ -0,0 +1,49 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package grendel;
|
||||
|
||||
import calypso.util.Preferences;
|
||||
import calypso.util.PreferencesFactory;
|
||||
|
||||
import grendel.ui.MessageDisplayManager;
|
||||
import grendel.ui.MultiMessageDisplayManager;
|
||||
import grendel.ui.UnifiedMessageDisplayManager;
|
||||
|
||||
/**
|
||||
* This launches the Grendel GUI.
|
||||
*/
|
||||
|
||||
public class Main {
|
||||
static MessageDisplayManager fManager;
|
||||
|
||||
public static void main(String argv[]) {
|
||||
Preferences prefs = PreferencesFactory.Get();
|
||||
String pref = prefs.getString("mail.layout", "multi_pane");
|
||||
|
||||
if (pref.equals("multi_pane")) {
|
||||
fManager = new UnifiedMessageDisplayManager();
|
||||
} else {
|
||||
fManager = new MultiMessageDisplayManager();
|
||||
}
|
||||
MessageDisplayManager.SetDefaultManager(fManager);
|
||||
fManager.displayMaster();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License
|
||||
# Version 1.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.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
# the License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Grendel mail/news client.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
SUBDIRS= \
|
||||
addressbook \
|
||||
calypso \
|
||||
composition \
|
||||
dnd \
|
||||
filters \
|
||||
integrator \
|
||||
mime \
|
||||
prefs \
|
||||
search \
|
||||
storage \
|
||||
ui \
|
||||
util \
|
||||
view \
|
||||
widgets \
|
||||
$(NULL)
|
||||
|
||||
SRCS= \
|
||||
Main.java \
|
||||
TestFolderViewer.java \
|
||||
$(NULL)
|
||||
|
||||
# SelfTest.java \
|
||||
|
||||
|
||||
include rules.mk
|
||||
|
||||
TARFILE=/tmp/grendel.tar.gz
|
||||
tar::
|
||||
@echo writing $(TARFILE)... ; \
|
||||
dir=`pwd | sed 's@^.*/\([^/]*\)$$@\1@'` ; \
|
||||
cd .. ; tar -vcf - $$dir \
|
||||
--exclude '*.class' \
|
||||
--exclude '*.bak' \
|
||||
--exclude '*~' \
|
||||
--exclude 'core' \
|
||||
| gzip -v9 > $(TARFILE)
|
|
@ -0,0 +1,5 @@
|
|||
This is Grendel -- a Java mail/news client.
|
||||
|
||||
It is incomplete, and currently has no active maintainer.
|
||||
|
||||
See http://www.mozilla.org/projects/grendel/ for more info.
|
|
@ -0,0 +1,245 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Terry Weissman <terry@netscape.com>, 3 Dec 1997.
|
||||
*/
|
||||
|
||||
package grendel;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.mail.Authenticator;
|
||||
import javax.mail.PasswordAuthentication;
|
||||
import javax.mail.Session;
|
||||
|
||||
import selftest.SelfTestRoot;
|
||||
|
||||
/**
|
||||
* This is the base grendel SelfTest. Running this classes main() will
|
||||
* execute the main() of all the SelfTest classes within the Grendel
|
||||
* project.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* This class also contains useful stuff for all of the Grendel SelfTest
|
||||
* classes to use. It is expected that all of those classes will inherit
|
||||
* from this one.
|
||||
*/
|
||||
|
||||
public class SelfTest extends SelfTestRoot {
|
||||
/** The Properties instance that all the javamail stuff will use. We try not
|
||||
to use calypso.util.Preferences during SelfTest, because there's no real
|
||||
way to control the values to be found there. Typically, your SelfTest
|
||||
code will stuff values into this Properties database so that the Store
|
||||
you're using will pull those values out. */
|
||||
static protected Properties props;
|
||||
|
||||
/** A stupid authenticator that we use to stuff in name/password info into
|
||||
our tests. */
|
||||
static private StupidAuthenticator authenticator;
|
||||
|
||||
/** The javax.mail.Session object. This is created for you by startTests. */
|
||||
static protected Session session;
|
||||
|
||||
/** The directory where you can store temporary stuff. If you want to use
|
||||
this, be sure to call makePlayDir() at the beginning of your test; that
|
||||
will ensure that the directory exists and is empty. */
|
||||
static protected File playdir = new File("selftestdir");
|
||||
|
||||
|
||||
/** Run all the grendel selftests. Every package within grendel ought to
|
||||
add itself here. */
|
||||
public static void main(String args[]) {
|
||||
grendel.storage.SelfTest.main(args);
|
||||
}
|
||||
|
||||
|
||||
/** Initialize things. If a subclass overrides this method, it must call
|
||||
this superclass's method (via super.startTests())
|
||||
The framework requires args to be passed down to SelfTestRoot.startTests.*/
|
||||
public void startTests(String args[]) {
|
||||
super.startTests(args);
|
||||
|
||||
// ###HACKHACKHACK Remove me when javamail fixes their stuff.
|
||||
java.io.File mailcapfile = new java.io.File("mailcap");
|
||||
if (!mailcapfile.exists()) {
|
||||
try {
|
||||
(new java.io.RandomAccessFile(mailcapfile, "rw")).close();
|
||||
writeMessage(null, "setup", "*** Created empty mailcap file in current");
|
||||
writeMessage(null, "setup", "*** directory (to work around buggy javamail");
|
||||
writeMessage(null, "setup", "*** software from JavaSoft).");
|
||||
} catch (java.io.IOException e) {
|
||||
writeMessage(null, "setup", "*** Couldn't create empty mailcap file: " + e);
|
||||
writeMessage(null, "setup", "*** Immanent crash is likely due to buggy");
|
||||
writeMessage(null, "setup", "*** javamail software from JavaSoft.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (session == null) {
|
||||
props = new Properties();
|
||||
authenticator = new StupidAuthenticator();
|
||||
session = Session.getDefaultInstance(props, authenticator);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Clean up at the end. If a subclass overrides this method, it must call
|
||||
this superclass's method (via super.endTests()) */
|
||||
|
||||
public void endTests() {
|
||||
cleanPlayDirectory();
|
||||
super.endTests();
|
||||
}
|
||||
|
||||
/** Stuff in the name and password we want to be used for the next test. */
|
||||
public void setUserAndPassword(String user, String password) {
|
||||
authenticator.set(user, password);
|
||||
}
|
||||
|
||||
static private boolean firsttime = true;
|
||||
|
||||
/** Creates an empty directory for your test to put stuff into. If a
|
||||
previously running test made one, it gets blown away.
|
||||
<p>
|
||||
The very first time this is called, we make sure that the directory doesn't
|
||||
already exist. We want to make sure not to blow away something that was
|
||||
already sitting on disk that doesn't belong to us. */
|
||||
public void makePlayDir() {
|
||||
if (firsttime) {
|
||||
if (playdir.exists()) {
|
||||
throw new
|
||||
Error("A directory or file named selftestdir already exists. " +
|
||||
"It must be moved or deleted before SelfTest can be run.");
|
||||
}
|
||||
}
|
||||
firsttime = false;
|
||||
cleanPlayDirectory();
|
||||
if (!playdir.mkdirs()) {
|
||||
throw new
|
||||
Error("Couldn't create a directory named selftestdir, so " +
|
||||
"SelfTest can't be run.");
|
||||
}
|
||||
}
|
||||
|
||||
/** Recursively cleans out the contents of the given directory. Potentially
|
||||
very dangerous! */
|
||||
public void cleanDirectory(File dir) {
|
||||
String [] list = dir.list();
|
||||
for (int i=0 ; i<list.length ; i++) {
|
||||
File f = new File(dir, list[i]);
|
||||
if (f.isDirectory()) {
|
||||
cleanDirectory(f);
|
||||
}
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/** Blows away the play directory. Since endTests() calls this, there
|
||||
generally won't be any reason for anyone else to. */
|
||||
public void cleanPlayDirectory() {
|
||||
if (playdir.exists()) {
|
||||
cleanDirectory(playdir);
|
||||
playdir.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/** Given a throwable, return as a string the stack trace from it. */
|
||||
public String getStackTrace(Throwable t) {
|
||||
StringWriter s = new StringWriter();
|
||||
PrintWriter p = new PrintWriter(s, true);
|
||||
t.printStackTrace(p);
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
static byte copybuf[] = new byte[4096];
|
||||
|
||||
|
||||
/** Takes a file from the jar file and stores it into the play directory.
|
||||
@param resname The name of the resource to grab from the jar file. This
|
||||
name is interpreted relative to the package that your SelfTest subclass
|
||||
is in.
|
||||
@param filename The name of the file to create. This name is interpreted
|
||||
relative to the playdir. */
|
||||
public void installFile(String resname, String filename) {
|
||||
try {
|
||||
InputStream in = getClass().getResourceAsStream(resname);
|
||||
if (in == null) {
|
||||
throw new Error("Can't open resource as stream: " + resname);
|
||||
}
|
||||
FileOutputStream out = new FileOutputStream(new File(playdir, filename));
|
||||
int length;
|
||||
while ((length = in.read(copybuf)) > 0) {
|
||||
out.write(copybuf, 0, length);
|
||||
}
|
||||
in.close();
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
throw new Error("IOException " + e + " while installing file " + filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Given a long that represents a time, returns a String representation of
|
||||
it suitable for putting in a log message. */
|
||||
public String prettyTime(long time) {
|
||||
return
|
||||
DateFormat.getDateTimeInstance(DateFormat.FULL,
|
||||
DateFormat.FULL).format(new Date(time)) +
|
||||
" (" + time + ")";
|
||||
}
|
||||
|
||||
|
||||
/** Report a bug that we already know about and that has an outstanding bug
|
||||
report sitting in the bug database. */
|
||||
|
||||
public void writeKnownBug(Object o, String methodName, int bugnum,
|
||||
String message)
|
||||
{
|
||||
// Should this be a warning or fatal? I dunno!
|
||||
writeWarning(o, methodName, "Known bug " + bugnum + ": " + message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class StupidAuthenticator extends Authenticator {
|
||||
String user;
|
||||
String password;
|
||||
|
||||
StupidAuthenticator() {}
|
||||
|
||||
void set(String u, String p) {
|
||||
user = u;
|
||||
password = p;
|
||||
}
|
||||
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(user, password);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,279 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Jamie Zawinski <jwz@mozilla.org>, 7-Sep-98.
|
||||
*/
|
||||
|
||||
package grendel;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Folder;
|
||||
import javax.mail.Session;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.Enumeration;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Date;
|
||||
|
||||
import calypso.util.ByteBuf;
|
||||
import calypso.util.ArrayEnumeration;
|
||||
import calypso.util.QSort;
|
||||
import calypso.util.Comparer;
|
||||
import calypso.util.NetworkDate;
|
||||
|
||||
import grendel.storage.BerkeleyStore;
|
||||
import grendel.storage.MessageExtra;
|
||||
|
||||
import grendel.view.FolderView;
|
||||
import grendel.view.FolderViewFactory;
|
||||
import grendel.view.MessageSetView;
|
||||
import grendel.view.ViewedMessage;
|
||||
|
||||
|
||||
class TestFolderViewer {
|
||||
|
||||
public static void main(String args[])
|
||||
throws IOException, MessagingException {
|
||||
if (args.length != 1) {
|
||||
System.out.println("usage: TestFolderViewer <mail-folder-pathname>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// First, split the directory and file name, and store the directory
|
||||
// in the "mail.directory" property (since JavaMail expects that.)
|
||||
//
|
||||
File pathname = new File(new File(args[0]).getAbsolutePath());
|
||||
String dir = pathname.getParent();
|
||||
String name = pathname.getName();
|
||||
|
||||
Properties props = new Properties();
|
||||
props.put("mail.directory", dir);
|
||||
|
||||
// Make the global "session" and "store" object.
|
||||
//
|
||||
Session session = Session.getDefaultInstance(props, null);
|
||||
BerkeleyStore store = new BerkeleyStore(session);
|
||||
|
||||
// Parse the folder. This will use a .summary file if one exists and is
|
||||
// up to date; otherwise, it will parse the whole folder. The `list'
|
||||
// array will hold Message (really, BerkeleyMessage) objects representing
|
||||
// each of the messages in the folder. Message objects are lightweight:
|
||||
// really they are just info like sender/subject/offset-in-file, etc.
|
||||
//
|
||||
System.out.println("Folder " + new File(dir, name));
|
||||
Folder folder = store.getDefaultFolder().getFolder(name);
|
||||
Message list[] = folder.getMessages();
|
||||
System.out.println("Found " + list.length + " messages.");
|
||||
|
||||
// Print out a summary of the contents of the folder.
|
||||
threadAndPrint(folder, MessageSetView.DATE, true);
|
||||
|
||||
// Interact with the user.
|
||||
mainLoop(folder);
|
||||
}
|
||||
|
||||
|
||||
// Gag -- for some reason our Message objects don't have getMessageNumber()
|
||||
// set in them (see FolderBase.noticeInitialMessage()) so until this is
|
||||
// fixed, let's kludge around it by keeping track of the index of the
|
||||
// message in its folder externally, in this hash table. This is totally
|
||||
// the wrong thing, but for now, it's expedient.
|
||||
//
|
||||
static Hashtable msgnum_kludge;
|
||||
|
||||
static void threadAndPrint(Folder folder, int sort_type, boolean thread_p) {
|
||||
FolderView view = FolderViewFactory.Make(folder);
|
||||
int order[] = { sort_type, MessageSetView.NUMBER };
|
||||
|
||||
// See "gag" comment above.
|
||||
// Populate the msgnum_kludge with message -> folder-index numbers.
|
||||
msgnum_kludge = new Hashtable();
|
||||
try {
|
||||
for (int i = 0; i < folder.getMessageCount(); i++)
|
||||
msgnum_kludge.put(folder.getMessage(i+1), new Integer(i+1));
|
||||
} catch (MessagingException e) {
|
||||
System.out.println("Error: " + e);
|
||||
}
|
||||
|
||||
System.out.println("Sorting by " +
|
||||
(sort_type == MessageSetView.NUMBER ? "number" :
|
||||
sort_type == MessageSetView.DATE ? "date" :
|
||||
sort_type == MessageSetView.SUBJECT ? "subject" :
|
||||
sort_type == MessageSetView.AUTHOR ? "author" :
|
||||
sort_type == MessageSetView.READ ? "read" :
|
||||
sort_type == MessageSetView.FLAGGED ? "flagged" :
|
||||
sort_type == MessageSetView.SIZE ? "size" :
|
||||
sort_type == MessageSetView.DELETED ? "deleted" :"?")
|
||||
+ ".");
|
||||
|
||||
System.out.println(thread_p ? "Threading." : "Not threading.");
|
||||
|
||||
// Tell the FolderView how to sort/thread, and then do it.
|
||||
//
|
||||
view.setSortOrder(order);
|
||||
view.setIsThreaded(thread_p);
|
||||
view.reThread();
|
||||
|
||||
// Now show the result.
|
||||
printThread(view.getMessageRoot(), 0);
|
||||
}
|
||||
|
||||
|
||||
static void printThread(ViewedMessage vm, int depth) {
|
||||
Message msg = (Message) vm.getMessage();
|
||||
String str = "";
|
||||
|
||||
for (int i = 0; i < depth; i++)
|
||||
str += " ";
|
||||
|
||||
if (msg == null) {
|
||||
// A ViewedMessage with no Message inside is a dummy container, holding
|
||||
// a thread together (for example, when the parent message of two
|
||||
// siblings is not present in the folder (expired or deleted.))
|
||||
//
|
||||
str += " [dummy]";
|
||||
|
||||
} else {
|
||||
|
||||
// Construct a string describing this message.
|
||||
//
|
||||
String a = "", s = "", n = "";
|
||||
Date d = null;
|
||||
|
||||
try {
|
||||
a = ((MessageExtra) msg).getAuthor();
|
||||
} catch (MessagingException e) {
|
||||
}
|
||||
|
||||
try {
|
||||
s = msg.getSubject();
|
||||
} catch (MessagingException e) {
|
||||
}
|
||||
|
||||
// See "gag" comment, above.
|
||||
int ni = ((Integer) msgnum_kludge.get(msg)).intValue() - 1;
|
||||
// int ni = msg.getMessageNumber();
|
||||
|
||||
n = "" + ni;
|
||||
if (ni < 10) n += " ";
|
||||
else if (ni < 100) n += " ";
|
||||
else if (ni < 1000) n += " ";
|
||||
else if (ni < 10000) n += " ";
|
||||
|
||||
str = n + str;
|
||||
|
||||
int L = str.length();
|
||||
|
||||
if (a.length() > 23-L) a = a.substring(0, 23-L);
|
||||
if (s.length() > 23) s = s.substring(0, 23);
|
||||
|
||||
str += a;
|
||||
for (int i = L+a.length(); i < 25; i++)
|
||||
str += " ";
|
||||
|
||||
str += s;
|
||||
for (int i = s.length(); i < 25; i++)
|
||||
str += " ";
|
||||
|
||||
try {
|
||||
d = msg.getSentDate();
|
||||
} catch (MessagingException e) {
|
||||
}
|
||||
if (d != null && d.getTime() != 0)
|
||||
str += d;
|
||||
else
|
||||
str += "date unknown";
|
||||
}
|
||||
|
||||
// Print the string describing this message.
|
||||
System.out.println(str);
|
||||
|
||||
// If this message has children, print them now (indented.)
|
||||
// After printing this message's children/grandchildren,
|
||||
// move on and print the next message in the list. (Note
|
||||
// that we're walking the list by recursing, but that's
|
||||
// probably ok, as its tail-recursion.)
|
||||
//
|
||||
ViewedMessage next = vm.getNext();
|
||||
ViewedMessage kid = vm.getChild();
|
||||
if (kid != null) printThread(kid, depth+1);
|
||||
if (next != null) printThread(next, depth);
|
||||
}
|
||||
|
||||
|
||||
static void mainLoop(Folder f) throws IOException {
|
||||
|
||||
DataInputStream in = new DataInputStream(System.in);
|
||||
|
||||
while (true) {
|
||||
|
||||
// Read a line from the user; parse an integer from it; and dump
|
||||
// the selected message to stdout. Then repeat.
|
||||
//
|
||||
System.out.print("\nDisplay which message: ");
|
||||
String s = in.readLine();
|
||||
try {
|
||||
int n = Integer.parseInt(s, 10);
|
||||
System.out.println("Displaying message " + n + ".");
|
||||
|
||||
try {
|
||||
Message m = f.getMessage(n+1);
|
||||
|
||||
try {
|
||||
InputStream stream =
|
||||
((MessageExtra)m).getInputStreamWithHeaders();
|
||||
// if (makeRealHTML) {
|
||||
// stream = new MakeItHTML(stream).getHTMLInputStream();
|
||||
// }
|
||||
InputStreamReader reader = new InputStreamReader(stream);
|
||||
char buff[] = new char[4096];
|
||||
int count;
|
||||
System.out.println("\n-----------");
|
||||
while ((count = reader.read(buff, 0, 4096)) != -1) {
|
||||
System.out.println(new String(buff, 0, count));
|
||||
}
|
||||
System.out.println("\n-----------");
|
||||
} catch (MessagingException e) {
|
||||
System.out.println("Error: " + e);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Error: " + e);
|
||||
}
|
||||
|
||||
} catch (MessagingException e) {
|
||||
System.out.println("Error: " + e);
|
||||
}
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
System.out.println("That's not a number.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,692 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package grendel.addressbook;
|
||||
|
||||
import grendel.addressbook.AddressCard.*;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import com.sun.java.swing.*;
|
||||
import com.sun.java.swing.text.*;
|
||||
import com.sun.java.swing.ImageIcon;
|
||||
import com.sun.java.swing.table.*;
|
||||
//import com.sun.java.swing.table.DefaultTableModel;
|
||||
import com.sun.java.swing.event.TableModelEvent;
|
||||
import com.sun.java.swing.border.EmptyBorder;
|
||||
|
||||
import netscape.ldap.*;
|
||||
import netscape.orion.toolbars.*;
|
||||
import netscape.orion.menus.NsMenuManager;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Lester Schueler
|
||||
*/
|
||||
public class AddressBook extends JFrame {
|
||||
private Hashtable mCommands;
|
||||
private Hashtable mMenuItems;
|
||||
|
||||
private JMenuBar mMenubar;
|
||||
private NSToolbar mTtoolbar;
|
||||
// private Component mStatusbar;
|
||||
private JTable mTable;
|
||||
private JButton mSearchButton;
|
||||
protected DataSourceList mDataSourceList;
|
||||
protected JComboBox mSearchSource;
|
||||
protected JTextField mSearchField;
|
||||
|
||||
public static void main(String[] args) {
|
||||
AddressBook AddressBookFrame = new AddressBook();
|
||||
AddressBookFrame.addWindowListener(new AppCloser());
|
||||
AddressBookFrame.show();
|
||||
}
|
||||
|
||||
protected static final class AppCloser extends WindowAdapter {
|
||||
public void windowClosing(WindowEvent e) {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
//***************************
|
||||
class DataSource {
|
||||
private String mReadableName;
|
||||
private String mDomainName;
|
||||
private int mPort;
|
||||
|
||||
DataSource (String aReadableName, String aDomainName) {
|
||||
this (aReadableName, aDomainName, 389);
|
||||
}
|
||||
|
||||
DataSource (String aReadableName, String aDomainName, int aPort) {
|
||||
mReadableName = aReadableName;;
|
||||
mDomainName = aDomainName;
|
||||
mPort = aPort;
|
||||
}
|
||||
|
||||
public String getReadableName () { return mReadableName; }
|
||||
public String getDomainName () { return mDomainName; }
|
||||
public int getPort () { return mPort; }
|
||||
}
|
||||
|
||||
//***************************
|
||||
class DataSourceList {
|
||||
private Vector mDataSources;
|
||||
|
||||
DataSourceList () {
|
||||
mDataSources = new Vector ();
|
||||
}
|
||||
|
||||
public Enumeration getEnumeration () { return mDataSources.elements(); }
|
||||
public void addEntry (DataSource aDataSource) { mDataSources.addElement (aDataSource); }
|
||||
|
||||
public DataSource find (String aReadableName) {
|
||||
for (Enumeration e = mDataSources.elements() ; e.hasMoreElements() ;) {
|
||||
DataSource ds = (DataSource) e.nextElement();
|
||||
|
||||
if (ds.getReadableName ().equalsIgnoreCase(aReadableName))
|
||||
return ds;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public AddressBook() {
|
||||
super("Address Book");
|
||||
|
||||
setBackground(Color.lightGray);
|
||||
//setBorderStyle(JPanel.ETCHED);
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
// addWindowListener(new FrameHider());
|
||||
|
||||
//create menubar (top)
|
||||
//merge both the editors commands with this applications commands.
|
||||
mMenubar = NsMenuManager.createMenuBar("grendel.addressbook.Menus", "grendel.addressbook.MenuLabels", "mainMenubar", defaultActions);
|
||||
|
||||
//collapsble panels holds toolbar.
|
||||
CollapsibleToolbarPanel collapsePanel = new CollapsibleToolbarPanel(this);
|
||||
collapsePanel.setBorder (new EmptyBorder(5,5,5,5));
|
||||
|
||||
//toolbar buttons
|
||||
mTtoolbar = createToolbar();
|
||||
|
||||
//collapsible item
|
||||
collapsePanel.add(mTtoolbar);
|
||||
|
||||
//create status bar (bottom)
|
||||
// mStatusbar = createStatusbar();
|
||||
|
||||
JPanel panel1 = new JPanel();
|
||||
panel1.setLayout(new BorderLayout());
|
||||
panel1.add(collapsePanel, BorderLayout.NORTH);
|
||||
|
||||
//hack togetther the data sources.
|
||||
mDataSourceList = new DataSourceList ();
|
||||
mDataSourceList.addEntry (new DataSource ("Four11 Directory", "ldap.four11.com"));
|
||||
mDataSourceList.addEntry (new DataSource ("InfoSpace Directory", "ldap.infospace.com"));
|
||||
mDataSourceList.addEntry (new DataSource ("WhoWhere Directory", "ldap.whowhere.com"));
|
||||
|
||||
//Create address panel
|
||||
AddressPanel addressPanel = new AddressPanel (mDataSourceList);
|
||||
panel1.add(addressPanel, BorderLayout.CENTER);
|
||||
|
||||
add(mMenubar, BorderLayout.NORTH);
|
||||
add(panel1, BorderLayout.CENTER);
|
||||
|
||||
setSize (600, 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide this frame.
|
||||
*/
|
||||
protected void hideThisFrame () {
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles windowClosing for window listener.
|
||||
*/
|
||||
protected class FrameHider extends WindowAdapter {
|
||||
public void windowClosing(WindowEvent e) {
|
||||
hideThisFrame();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the hosting frame, for the file-chooser dialog.
|
||||
*/
|
||||
protected Frame getParentFrame() {
|
||||
// for (Container p = getParent(); p != null; p = p.getParent()) {
|
||||
// if (p instanceof Frame) {
|
||||
// return (Frame) p;
|
||||
// }
|
||||
// }
|
||||
return this;
|
||||
}
|
||||
|
||||
//**********************
|
||||
//**********************
|
||||
// menus
|
||||
private JMenuBar menubar;
|
||||
|
||||
//"File" actions
|
||||
public static final String newCardTag ="newCard";
|
||||
public static final String newListTag ="newList";
|
||||
public static final String importTag ="import";
|
||||
public static final String saveAsTag ="saveAs";
|
||||
public static final String callTag ="call";
|
||||
public static final String closeWindowTag ="closeWindow";
|
||||
|
||||
// "file->new" actions
|
||||
public static final String navigatorWindowTag ="navigatorWindow";
|
||||
public static final String messageTag ="message";
|
||||
public static final String blankPageTag ="blankPage";
|
||||
public static final String pageFromTemplateTag ="pageFromTemplate";
|
||||
public static final String pageFromWizardTag ="pageFromWizard";
|
||||
|
||||
//"Edit" actions
|
||||
public static final String undoTag ="undo";
|
||||
public static final String redoTag ="redo";
|
||||
public static final String deleteTag ="delete";
|
||||
public static final String searchDirectoryTag ="searchDirectory";
|
||||
public static final String HTMLDomainsTag ="HTMLDomains";
|
||||
public static final String cardPropertiesTag ="cardProperties";
|
||||
public static final String preferencesTag ="preferences";
|
||||
|
||||
//"View" actions
|
||||
public static final String hideMessageToolbarTag ="hideMessageToolbar";
|
||||
public static final String byTypeTag ="byType";
|
||||
public static final String byNameTag ="byName";
|
||||
public static final String byEmailAddressTag ="byEmailAddress";
|
||||
public static final String byComapanyTag ="byComapany";
|
||||
public static final String byCityTag ="byCity";
|
||||
public static final String byNicknameTag ="byNickname";
|
||||
public static final String sortAscendingTag ="sortAscending";
|
||||
public static final String sortDescendingTag ="sortDescending";
|
||||
public static final String myAddressBookCardTag ="myAddressBookCard";
|
||||
|
||||
// --- action implementations -----------------------------------
|
||||
private Action[] defaultActions = {
|
||||
//"File" actions
|
||||
new NewCard(),
|
||||
// new NewList(),
|
||||
// new Import(),
|
||||
new SaveAs(),
|
||||
// new Call(),
|
||||
new CloseWindow()
|
||||
|
||||
// "file->new" actions
|
||||
// new NavigatorWindow(),
|
||||
// new Message(),
|
||||
// new BlankPage(),
|
||||
// new PageFromTemplate(),
|
||||
// new PageFromWizard(),
|
||||
|
||||
//"Edit" actions
|
||||
// new Undo(),
|
||||
// new Redo(),
|
||||
// new Delete(),
|
||||
// new SearchDirectory(),
|
||||
// new HTMLDomains(),
|
||||
// new CardProperties(),
|
||||
// new Preferences(),
|
||||
|
||||
//"View" actions
|
||||
// new HideMessageToolbar(),
|
||||
// new ByType(),
|
||||
// new ByName(),
|
||||
// new ByEmailAddress(),
|
||||
// new ByCompany(),
|
||||
// new ByCity(),
|
||||
// new ByNickname(),
|
||||
// new SortAscending(),
|
||||
// new SortDescending(),
|
||||
// new MyAddressBookCard(),
|
||||
// new WrapLongLines()
|
||||
};
|
||||
|
||||
//-----------------------
|
||||
//"File" actions
|
||||
//-----------------------
|
||||
/**
|
||||
*/
|
||||
class NewCard extends AbstractAction {
|
||||
NewCard() {
|
||||
super(newCardTag);
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
NewCardDialog aDialog = new NewCardDialog(getParentFrame());
|
||||
|
||||
//display the new card dialog
|
||||
aDialog.show ();
|
||||
aDialog.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class SaveAs extends AbstractAction {
|
||||
SaveAs() {
|
||||
super(saveAsTag);
|
||||
setEnabled(true);
|
||||
}
|
||||
public void actionPerformed(ActionEvent ae) {
|
||||
NewCardDialog aDialog = new NewCardDialog(getParentFrame());
|
||||
|
||||
//display the new card dialog
|
||||
aDialog.show ();
|
||||
aDialog.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class CloseWindow extends AbstractAction {
|
||||
CloseWindow() {
|
||||
super(closeWindowTag);
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
//hide after send.
|
||||
hideThisFrame();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------
|
||||
// "file->new" actions
|
||||
//-----------------------
|
||||
|
||||
//-----------------------
|
||||
//"Edit" actions
|
||||
//-----------------------
|
||||
class Undo extends AbstractAction {
|
||||
Undo() {
|
||||
super(undoTag);
|
||||
setEnabled(true);
|
||||
}
|
||||
public void actionPerformed(ActionEvent e) {}
|
||||
}
|
||||
|
||||
//-----------------------
|
||||
//"View" actions
|
||||
//-----------------------
|
||||
class HideMessageToolbar extends AbstractAction {
|
||||
HideMessageToolbar() {
|
||||
super(hideMessageToolbarTag);
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {}
|
||||
}
|
||||
|
||||
//-----------------------
|
||||
//-----------------------
|
||||
class Search extends AbstractAction {
|
||||
Search() {
|
||||
super(newListTag);
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String readableName = (String) mSearchSource.getSelectedItem();
|
||||
int index = mSearchSource.getSelectedIndex();
|
||||
|
||||
DataSource ds = mDataSourceList.find (readableName);
|
||||
if (null != ds) {
|
||||
|
||||
//get the text to search for.
|
||||
String textToSearchFor = mSearchField.getText();
|
||||
|
||||
if (!textToSearchFor.trim().equals ("")) {
|
||||
DataModel dm = (DataModel) mTable.getModel ();
|
||||
dm.reloadData (ds.getDomainName(), ds.getPort(), textToSearchFor);
|
||||
|
||||
//repaint the table with results.
|
||||
mTable.repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Toolbar
|
||||
* @see addToolbarButton
|
||||
*/
|
||||
private NSToolbar createToolbar() {
|
||||
|
||||
NSToolbar toolBar = new NSToolbar();
|
||||
addToolbarButton(toolBar, null, "images/newcard.gif", "Create a new card");
|
||||
addToolbarButton(toolBar, null, "images/newlist.gif", "Create a new list");
|
||||
addToolbarButton(toolBar, null, "images/properties.gif", "Edit the selected card");
|
||||
addToolbarButton(toolBar, null, "images/newmsg.gif", "New Message (Ctrl+M)");
|
||||
addToolbarButton(toolBar, null, "images/directory.gif", "Look up an address");
|
||||
addToolbarButton(toolBar, null, "images/call.gif", "Start Netscape Conference");
|
||||
addToolbarButton(toolBar, null, "images/delete.gif", "Delete selected cards <Del>");
|
||||
|
||||
return toolBar;
|
||||
}
|
||||
|
||||
/**
|
||||
* create a toolbar button
|
||||
* @param aToolBar The parent toolbar to add this button to.
|
||||
* @param aActionListener Who you want to be notified when the button is pressed.
|
||||
* @param aImageName The image name for the button. like "save.gif"
|
||||
* @param aToolTip The buttons tool tip. like "Save the current file".
|
||||
* @see createToolbar
|
||||
*/
|
||||
public void addToolbarButton(NSToolbar aToolBar, AbstractAction aActionListener, String aImageName, String aToolTip) {
|
||||
NSButton b = new NSButton();
|
||||
|
||||
b.setHorizontalTextPosition(JButton.CENTER);
|
||||
b.setVerticalTextPosition(JButton.BOTTOM);
|
||||
b.setToolTipText(aToolTip);
|
||||
|
||||
// URL iconUrl = getClass().getResource("images/" + gifName + ".gif");
|
||||
b.setIcon(new ImageIcon(getClass().getResource(aImageName)));
|
||||
|
||||
// iconUrl = getClass().getResource("images/" + gifName + "-disabled.gif");
|
||||
// button.setDisabledIcon(ImageIcon.createImageIcon(iconUrl));
|
||||
|
||||
// iconUrl = getClass().getResource("images/" + gifName + "-depressed.gif");
|
||||
// button.setPressedIcon(ImageIcon.createImageIcon(iconUrl));
|
||||
|
||||
// iconUrl = getClass().getResource("images/" + gifName + "-rollover.gif");
|
||||
// button.setRolloverIcon(ImageIcon.createImageIcon(iconUrl));
|
||||
|
||||
|
||||
// JButton b = new JButton(new ImageIcon(aImageName));
|
||||
// b.setToolTipText(aToolTip);
|
||||
// b.setPad(new Insets(3,3,3,3));
|
||||
// b.addActionListener(aActionListener);
|
||||
|
||||
aToolBar.addItem(b);
|
||||
}
|
||||
|
||||
private String getFirstEnum (Enumeration enumVals) {
|
||||
if (enumVals.hasMoreElements())
|
||||
return (String) enumVals.nextElement();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Vector queryLDAP (String aServerName, int aPort, String aSearchString) {
|
||||
|
||||
Vector retVecVec = new Vector(); //return vector of vectors.
|
||||
|
||||
// try {
|
||||
//open a connection to the LDAP server
|
||||
System.out.println ("Opening server");
|
||||
ICardSource Four11AddressBook = new LDAP_Server (aServerName);
|
||||
|
||||
//create the query
|
||||
ITerm query = new TermEqual (new AC_Attribute ("sn", aSearchString));
|
||||
|
||||
String[] attributes = {"sn", "cn", "o", "mail", "city"};
|
||||
|
||||
//query the LDAP server.
|
||||
System.out.println ("Send query");
|
||||
ICardSet cardSet = Four11AddressBook.getCardSet (query, attributes);
|
||||
|
||||
//Sort the list.
|
||||
// String[] sortOrder = {"givenname", "surname"};
|
||||
// cardSet.sort (sortOrder);
|
||||
|
||||
//hack. I've put the for loop in a try block to catch the exception
|
||||
//thrown when cardEnum.hasMoreElements() incorrectly returns true.
|
||||
try {
|
||||
//enumerate thru the cards.
|
||||
for (Enumeration cardEnum = cardSet.getEnumeration(); cardEnum.hasMoreElements(); ) {
|
||||
System.out.println ("got card");
|
||||
ICard card = (ICard) cardEnum.nextElement(); //get the addres card
|
||||
IAttributeSet attrSet = card.getAttributeSet (); //get the attributes for this card
|
||||
Vector thisRow = new Vector(6); //create a simple vector to hold the attributes values for this card.
|
||||
|
||||
String commonName = "";
|
||||
String organization = "";
|
||||
String mail = "";
|
||||
String phone = "";
|
||||
String city = "";
|
||||
String nickName = "";
|
||||
|
||||
// enumerate thru the card attributes.
|
||||
for (Enumeration attEnum = attrSet.getEnumeration(); attEnum.hasMoreElements(); ) {
|
||||
IAttribute attr = (IAttribute) attEnum.nextElement();
|
||||
String attrName = attr.getName();
|
||||
|
||||
if (attrName.equals ("cn")) {
|
||||
commonName = attr.getValue();
|
||||
}
|
||||
|
||||
else if (attrName.equals ("o")) {
|
||||
organization = attr.getValue();
|
||||
}
|
||||
|
||||
else if (attrName.equals ("mail")) {
|
||||
mail = attr.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
//create this row for the table.
|
||||
thisRow.addElement (commonName);
|
||||
thisRow.addElement (mail);
|
||||
thisRow.addElement (organization);
|
||||
thisRow.addElement (phone);
|
||||
thisRow.addElement (city);
|
||||
thisRow.addElement (nickName);
|
||||
|
||||
//add this row to the table
|
||||
retVecVec.addElement (thisRow);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
}
|
||||
// }
|
||||
// catch( LDAPException e ) {
|
||||
// System.out.println( "Error: " + e.toString() );
|
||||
// }
|
||||
|
||||
System.out.println ("Done.");
|
||||
return retVecVec;
|
||||
}
|
||||
|
||||
public class DataModel extends AbstractTableModel {
|
||||
private Vector mVecVec;
|
||||
private String[] mColumnNames;
|
||||
|
||||
public DataModel (String[] aNames) {
|
||||
super();
|
||||
mVecVec = new Vector ();
|
||||
mColumnNames = aNames;
|
||||
}
|
||||
|
||||
public int getRowCount() { return mVecVec.size(); }
|
||||
public int getColumnCount () { return mColumnNames.length; }
|
||||
public String getColumnName(int column) { return mColumnNames[column]; }
|
||||
public Class getColumnClass(int col) { return String.class; }
|
||||
public boolean isCellEditable(int row, int col) { return false;}
|
||||
|
||||
public void setValueAt(Object aValue, int row, int column) {
|
||||
((Vector)mVecVec.elementAt(row)).setElementAt(aValue, column);
|
||||
}
|
||||
|
||||
public void reloadData (String aServerName, int aPort, String aSearchString) {
|
||||
//reload the data from LDAP.
|
||||
mVecVec = queryLDAP (aServerName, aPort, aSearchString);
|
||||
}
|
||||
|
||||
public Object getValueAt(int row, int column) {
|
||||
return (((Vector)mVecVec.elementAt(row)).elementAt(column));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a status bar
|
||||
* @return
|
||||
* @see
|
||||
*/
|
||||
// protected Component createStatusbar() {
|
||||
// // need to do something reasonable here
|
||||
// StatusBar status = new StatusBar();
|
||||
// return status;
|
||||
// }
|
||||
|
||||
//***************************
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class StatusBar extends JPanel {
|
||||
public StatusBar() {
|
||||
super();
|
||||
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
|
||||
}
|
||||
|
||||
public void paint(Graphics g) {
|
||||
super.paint(g);
|
||||
}
|
||||
}
|
||||
|
||||
//***************************
|
||||
/**
|
||||
*/
|
||||
class AddressPanel extends JPanel {
|
||||
|
||||
public AddressPanel(DataSourceList aDataSourceList) {
|
||||
//super(true);
|
||||
|
||||
setBorder (new EmptyBorder(10,10,10,10));
|
||||
setLayout (new BorderLayout(10, 5));
|
||||
|
||||
add(createSearchPane(aDataSourceList), BorderLayout.NORTH);
|
||||
add(createTable(), BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
private Box createSearchPane (DataSourceList aDataSourceList) {
|
||||
//explaination
|
||||
JLabel explaination = new JLabel ("Type in the name you're looking for:");
|
||||
explaination.setAlignmentX((float)0.0); //align left
|
||||
|
||||
//text field
|
||||
mSearchField = new JTextField (20);
|
||||
mSearchField.setAlignmentX((float)0.0); //align left
|
||||
|
||||
//box for explain and text field
|
||||
Box innerBoxPane = new Box (BoxLayout.Y_AXIS);
|
||||
// innerBoxPane.setAlignmentY((float)0.0); //align to bottom
|
||||
innerBoxPane.add (explaination);
|
||||
innerBoxPane.add (mSearchField);
|
||||
|
||||
//drop down combo box
|
||||
mSearchSource = new JComboBox();
|
||||
mSearchSource.setAlignmentY((float)0.0); //align to bottom
|
||||
for (Enumeration e = aDataSourceList.getEnumeration() ; e.hasMoreElements() ;) {
|
||||
DataSource ds = (DataSource) e.nextElement();
|
||||
mSearchSource.addItem(ds.getReadableName());
|
||||
}
|
||||
|
||||
//label
|
||||
JLabel lbl = new JLabel ("in:");
|
||||
lbl.setAlignmentY((float)0.0); //align to bottom
|
||||
|
||||
//search button
|
||||
mSearchButton = new JButton ("Search");
|
||||
mSearchButton.addActionListener(new Search());
|
||||
mSearchButton.setAlignmentY((float)0.0); //align to bottom
|
||||
|
||||
Dimension spacer = new Dimension (10, 10);
|
||||
|
||||
//assemble all the pieces together.
|
||||
Box boxPane = new Box (BoxLayout.X_AXIS);
|
||||
|
||||
boxPane.add (innerBoxPane); //explaination and text field
|
||||
boxPane.add (Box.createRigidArea(spacer)); //spacer
|
||||
boxPane.add (lbl); //"in:" label
|
||||
boxPane.add (Box.createRigidArea(spacer)); //spacer
|
||||
boxPane.add (mSearchSource); //drop down combo box
|
||||
boxPane.add (Box.createRigidArea(spacer)); //spacer
|
||||
boxPane.add (mSearchButton); //search buttton
|
||||
|
||||
return boxPane;
|
||||
}
|
||||
|
||||
private JScrollPane createTable () {
|
||||
String[] columnNames = {
|
||||
"Name",
|
||||
"Email Address",
|
||||
"Organization",
|
||||
"Phone",
|
||||
"City",
|
||||
"Nickname"};
|
||||
|
||||
//create the data model.
|
||||
DataModel dm = new DataModel (columnNames);
|
||||
|
||||
//create the table.
|
||||
mTable = new JTable(dm);
|
||||
|
||||
// mTable.setAutoCreateColumnsFromModel(false);
|
||||
|
||||
// Add our columns into the column model
|
||||
// for (int columnIndex = 0; columnIndex < columnNames.length; columnIndex++){
|
||||
// Create a column object for each column of data
|
||||
// TableColumn newColumn = new TableColumn(columnNames[columnIndex]);
|
||||
|
||||
// Set a tool tip for the column header cell
|
||||
// TableCellRenderer renderer2 = newColumn.getHeaderRenderer();
|
||||
// if (renderer2 instanceof DefaultCellRenderer)
|
||||
// ((DefaultCellRenderer)renderer2).setToolTipText(columnNames[columnIndex]);
|
||||
|
||||
// newColumn.setWidth(200);
|
||||
// mTable.addColumn(newColumn);
|
||||
// }
|
||||
|
||||
//no selection, no grid.
|
||||
mTable.setColumnSelectionAllowed(false);
|
||||
mTable.setShowGrid(false);
|
||||
|
||||
// Put the table and header into a scrollPane
|
||||
JScrollPane scrollpane = JTable.createScrollPaneForTable(mTable);
|
||||
// JTableHeader tableHeader = mTable.getTableHeader();
|
||||
|
||||
// create and add the column heading to the scrollpane's
|
||||
// column header viewport
|
||||
// JViewport headerViewport = new JViewport();
|
||||
// headerViewport.setLayout(new BoxLayout(headerViewport, BoxLayout.X_AXIS));
|
||||
// headerViewport.add(tableHeader);
|
||||
// scrollpane.setColumnHeader(headerViewport);
|
||||
|
||||
// add the table to the viewport
|
||||
/// JViewport mainViewPort = scrollpane.getViewport();
|
||||
// mainViewPort.add(mTable);
|
||||
// mainViewPort.setBackground (Color.white);
|
||||
|
||||
// speed up resizing repaints by turning off live cell updates
|
||||
// tableHeader.setUpdateTableInRealTime(false);
|
||||
|
||||
//return the JScrollPane with the table in it.
|
||||
return scrollpane;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License
|
||||
# Version 1.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.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
# the License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Grendel mail/news client.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
SUBDIRS= \
|
||||
addresscard \
|
||||
$(NULL)
|
||||
|
||||
SRCS= \
|
||||
AddressBook.java \
|
||||
NewCardDialog.java \
|
||||
$(NULL)
|
||||
|
||||
include ../rules.mk
|
|
@ -0,0 +1,109 @@
|
|||
#
|
||||
# The contents of this file are subject to the Mozilla Public License
|
||||
# Version 1.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.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
# the License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Grendel mail/news client.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
# menubar definition for mail/news adress book
|
||||
# Lester Schueler 97/09/31
|
||||
|
||||
# main menu definition
|
||||
mainMenubar=file edit view communicator help
|
||||
|
||||
# "file" Menu definition
|
||||
file=new newCard newList import - saveAs call - close
|
||||
|
||||
# "file" Menu actions
|
||||
newCardAction =newCard
|
||||
newListAction =newList
|
||||
importAction =import
|
||||
saveAsAction =saveAs
|
||||
callAction =call
|
||||
closeAction =closeWindow
|
||||
|
||||
# "file->new" menu definition
|
||||
new=navigatorWindow message - blankPage pageFromTemplate pageFromWizard
|
||||
|
||||
# "file->new" Menu actions
|
||||
navigatorWindowAction =navigatorWindow
|
||||
messageAction =message
|
||||
blankPageAction =blankPage
|
||||
pageFromTemplateAction =pageFromTemplate
|
||||
pageFromWizardAction =pageFromWizard
|
||||
|
||||
# "edit" Menu definition
|
||||
edit=undo redo - delete - searchDirectory - HTMLDomains cardProperties preferences
|
||||
|
||||
# "edit" Menu actions
|
||||
undoAction =undo
|
||||
redoAction =redo
|
||||
deleteAction =delete
|
||||
searchDirectoryAction =searchDirectory
|
||||
HTMLDomainsAction =HTMLDomains
|
||||
cardPropertiesAction =cardProperties
|
||||
preferencesAction =preferences
|
||||
|
||||
# "view" menu definition
|
||||
view=hideABToolbar - byType byName byEmailAddress byComapany byCity byNickname - sortAscending sortDescending - myAddressBookCard
|
||||
|
||||
# "view" Menu actions
|
||||
hideABToolbarAction =hideABToolbar
|
||||
byTypeAction =byType
|
||||
byNameAction =byName
|
||||
byEmailAddressAction =byEmailAddress
|
||||
byComapanyAction =byComapany
|
||||
byCityAction =byCity
|
||||
byNicknameAction =byNickname
|
||||
sortAscendingAction =sortAscending
|
||||
sortDescendingAction =sortDescending
|
||||
myAddressBookCardAction =myAddressBookCard
|
||||
|
||||
# "communicator" menu definition
|
||||
communicator=navigator messenger collabra composer conference calendar IBM netcaster - dockComponentBar messageCenter bookmarks history javaConsolse securityInfo -
|
||||
|
||||
# "communicator" Menu actions
|
||||
#navigatorAction =navigator
|
||||
#messengerAction =messenger
|
||||
#collabraAction =collabra
|
||||
#composerAction =composer
|
||||
#conferenceAction =conference
|
||||
#calendarAction =calendar
|
||||
#IBMAction =IBM
|
||||
#NetcasterAction =netcaster
|
||||
#dockComponentBarAction =dockComponentBar
|
||||
#messageCenterAction =messageCenter
|
||||
#bookmarksAction =bookmarks
|
||||
#historyAction =history
|
||||
#javaConsolseAction =javaConsolse
|
||||
#securityInfoAction =securityInfo
|
||||
|
||||
# "communicator->bookmarks" menu definition
|
||||
bookmarks=bookmark1 bookmark2 bookmark3
|
||||
|
||||
# "help" menu definition
|
||||
help=helpContents releaseNotes productInfo - softwareUpdates registerNow memberServices - InternationUsers security netEtiquette - aboutPlugins aboutFontDisplayers aboutCommunicator
|
||||
|
||||
# "help" Menu actions
|
||||
#helpContentsAction =helpContents
|
||||
#releaseNotesAction =releaseNotes
|
||||
#productInfoAction =productInfo
|
||||
#softwareUpdatesAction =softwareUpdates
|
||||
#registerNowAction =registerNow
|
||||
#memberServicesAction =memberServices
|
||||
#InternationUsersAction =InternationUsers
|
||||
#securityAction =security
|
||||
#netEtiquetteAction =netEtiquette
|
||||
#aboutPluginsAction =aboutPlugins
|
||||
#aboutFontDisplayersAction =aboutFontDisplayers
|
||||
#aboutCommunicatorAction =aboutCommunicator
|
|
@ -0,0 +1,88 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package grendel.addressbook;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.*;
|
||||
|
||||
import com.sun.java.swing.*;
|
||||
|
||||
class NewCardDialog extends Dialog {
|
||||
|
||||
NewCardDialog(Frame aParent) {
|
||||
//FIX: Resource
|
||||
super(aParent, "Card for", true);
|
||||
|
||||
// setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
|
||||
|
||||
JComponent namePanel = createNamePanel ();
|
||||
add (namePanel);
|
||||
|
||||
// JComponent contactPanel = createContactPanel ();
|
||||
// add (contactPanel);
|
||||
|
||||
// JComponent netConfPanel = createNetConfPanel ();
|
||||
// add (netConfPanel);
|
||||
|
||||
setResizable(false);
|
||||
setSize (716, 515);
|
||||
}
|
||||
|
||||
private JPanel createNamePanel () {
|
||||
//the outer most panel has groove etched into it.
|
||||
JPanel pane = new JPanel(false);
|
||||
// pane.setLayout (new BoxLayout(pane, BoxLayout.Y_AXIS));
|
||||
|
||||
JTextField mFirstName = makeField ("First Name:", 20);
|
||||
pane.add (mFirstName);
|
||||
/*
|
||||
JTextField mLastName = makeField ("Last Name:", 20);
|
||||
pane.add (mLastName);
|
||||
|
||||
JTextField mOrganization = makeField ("Organization:", 20);
|
||||
pane.add (mOrganization);
|
||||
|
||||
JTextField mTitle = makeField ("Title:", 20);
|
||||
pane.add (mTitle);
|
||||
|
||||
JTextField mEmail = makeField ("Email Address:", 20);
|
||||
pane.add (mEmail);
|
||||
*/
|
||||
return pane;
|
||||
}
|
||||
|
||||
private JTextField makeField (String aTitle, int aCol) {
|
||||
// JPanel box = new JPanel (false);
|
||||
Box box = new Box (BoxLayout.X_AXIS);
|
||||
|
||||
JLabel title = new JLabel (aTitle);
|
||||
title.setAlignmentY((float)0.0); //bottom
|
||||
title.setAlignmentX((float)0.0); //left
|
||||
box.add (title);
|
||||
|
||||
JTextField textField = new JTextField (aCol);
|
||||
textField.setAlignmentY((float)0.0); //bottom
|
||||
textField.setAlignmentX((float)1.0); //right
|
||||
box.add (textField);
|
||||
|
||||
return textField;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
This is Grendel -- a Java mail/news client.
|
||||
|
||||
The grendel.addressbook package talks to LDAP, and provides a nice API
|
||||
to all things dealing with addressbook.
|
||||
|
||||
See http://www.mozilla.org/projects/grendel/ for more info.
|
|
@ -0,0 +1,209 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
import grendel.storage.intertwingle.*;
|
||||
import java.util.Enumeration;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
//import java.util.Vector;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public class ACS_Personal implements ICardSource, IQuerySet {
|
||||
private DB fDB;
|
||||
|
||||
public ACS_Personal (String FileName, boolean CreateOnOpen) {
|
||||
File DBFile = new File(FileName);
|
||||
try {
|
||||
fDB = new SimpleDB(DBFile);
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
/** Get the next card ID for this DB.
|
||||
*/
|
||||
private String getNextCardID () {
|
||||
int nextCardIntID = 0;
|
||||
String nextCardStrID;
|
||||
|
||||
try {
|
||||
//initalize the next card ID
|
||||
nextCardStrID = fDB.findFirst ("Control", "NextCardID", false);
|
||||
|
||||
//if the value wasn't found then assume this is the first time.
|
||||
if ((null == nextCardStrID) || (nextCardStrID.equals (""))) {
|
||||
nextCardIntID = 0;
|
||||
}
|
||||
|
||||
//if the value WAS found then try to extract an integer value from the text.
|
||||
else {
|
||||
try {
|
||||
nextCardIntID = Integer.valueOf(nextCardStrID).intValue();
|
||||
} catch (NumberFormatException nfe) {
|
||||
nextCardIntID = 0;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
nextCardIntID = 0;
|
||||
}
|
||||
|
||||
//create a string representation of the card's ID.
|
||||
nextCardStrID = String.valueOf(++nextCardIntID);
|
||||
|
||||
try {
|
||||
//write the new value out to the DB.
|
||||
fDB.assert ("Control", "NextCardID", nextCardStrID);
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
|
||||
return nextCardStrID;
|
||||
}
|
||||
|
||||
/**
|
||||
* closing the source
|
||||
*/
|
||||
public void close () {
|
||||
try {
|
||||
((BGDB) fDB).flushChanges();
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieveing address cards
|
||||
*/
|
||||
public ICardSet getCardSet (ITerm aQueryTerm, String[] anAttributesArray) {
|
||||
//get the card ID's that satidsfy the query.
|
||||
ACIDSet CardIDSet = aQueryTerm.evaluate_ACSP (this);
|
||||
|
||||
//create the address card set that'll be returned.
|
||||
AddressCardSet retCardSet = new AddressCardSet ();
|
||||
|
||||
for (int i = 0; i < CardIDSet.size(); i++) {
|
||||
//create an attribute set for the card.
|
||||
AddressCardAttributeSet attrSet = new AddressCardAttributeSet();
|
||||
|
||||
//get all attributes for this card.
|
||||
for (int j = 0; j < anAttributesArray.length; j++) {
|
||||
String attrName = anAttributesArray[j];
|
||||
|
||||
//read the attribute from the DB.
|
||||
try {
|
||||
String attrValue = fDB.findFirst((String) CardIDSet.elementAt(i), attrName, false);
|
||||
|
||||
//if found then add to the attribute set for this card.
|
||||
if (null != attrValue) {
|
||||
attrSet.add (new AddressCardAttribute (attrName, attrValue));
|
||||
}
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
|
||||
//create the new card, and add to the return card set.
|
||||
retCardSet.add (new AddressCard(this, attrSet));
|
||||
}
|
||||
|
||||
//return the card set
|
||||
return retCardSet;
|
||||
}
|
||||
|
||||
/** Add a single card to this addressbook.
|
||||
*/
|
||||
public void add (AddressCard aCard, boolean OverWrite) {
|
||||
//give the card a new ID
|
||||
String thisCardID = getNextCardID ();
|
||||
aCard.setID (thisCardID);
|
||||
|
||||
//get the set of attributes and enumerate thruough them.
|
||||
AddressCardAttributeSet attrSet = aCard.getAttributeSet();
|
||||
|
||||
for (Enumeration enum = attrSet.elements (); enum.hasMoreElements(); ) {
|
||||
//get the next attribute
|
||||
AddressCardAttribute attr = (AddressCardAttribute) enum.netxElement ();
|
||||
|
||||
//write the attribute to the DB
|
||||
try {
|
||||
fDB.assert (thisCardID, attr.getName(), attr.getValue());
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
/** Add a set of cards to this addressbook.
|
||||
*/
|
||||
public void add (AddressCardSet aCardSet, boolean OverWrite) {
|
||||
for (Enumeration enum = aCardSet.getCardEnumeration (); enum.hasMoreElements() ;) {
|
||||
AddressCard card = (AddressCard) enum.nextElement();
|
||||
addCard (card, OverWrite);
|
||||
}
|
||||
}
|
||||
|
||||
//*******************************
|
||||
//**** Operational functions ****
|
||||
//*******************************
|
||||
|
||||
/** Search the database for all cards that match this value
|
||||
* and return a set Adddress Card ID's (ACID's).
|
||||
*/
|
||||
public ACIDSet opEqual (AddressCardAttribute ACA) {
|
||||
ACIDSet retIDSet = new ACIDSet();
|
||||
|
||||
if (null != ACA) {
|
||||
//the RDFish DB returns an enumeration of a matching card ID's
|
||||
for (Enumeration enum = fDB.findAll(ACA.getName(), ACA.getValue (), false); enum.hasMoreElements() ;) {
|
||||
retIDSet.addElement (enum.nextElement());
|
||||
}
|
||||
}
|
||||
|
||||
return retIDSet;
|
||||
}
|
||||
|
||||
/** Search the database for all cards that DO NOT match this value
|
||||
* and return a set Adddress Card ID's (ACID's).
|
||||
*/
|
||||
public ACIDSet opNotEqual (AddressCardAttribute ACA) {
|
||||
ACIDSet retIDSet = new ACIDSet();
|
||||
|
||||
return retIDSet;
|
||||
}
|
||||
|
||||
/*
|
||||
1.Boolean RDF_HasAssertion (RDF_Resource u, RDF_Resource s, void* v, RDF_ValueType type, Boolean tv);
|
||||
Returns true if there is an arc in the graph whose origin is u, whose label is s, whose target is v and whose truth value is true.
|
||||
|
||||
2.void* RDF_GetSlotValue (RDF_Resource u, RDF_Resource s, RDF_ValueType type, Boolean inversep, Boolean tv);
|
||||
Returns the target (whose datatype is type) of (any) one of the arcs whose source is u, label is s and truth value is tv. If inversep is true,
|
||||
then it return the source (whose datatype is type) of (any) one of the arcs whose target is u, label is s and truth value is tv.
|
||||
|
||||
3.RDF_Cursor RDF_GetSlotValues (RDF_Resource u, RDF_Resource s, RDF_ValueType type, Boolean inversep, Boolean tv);
|
||||
Returns a cursor that can be used to enumerate through the targets (of datatype type) of the arcs whose source is u, label is s and truth
|
||||
value is tv. If inversep is true, then the cursor enumerates through the sources of the arcs whose label is s, target is u and truth value is tv.
|
||||
You can store your private data on the pdata field of the cursor. Cursors are cheap.
|
||||
|
||||
4.void* RDF_NextValue(RDF_Cursor c);
|
||||
Returns the next value from this cursor. Returns NULL if there are no more values. The fields value and type hold the value and datatype
|
||||
of the value respectively.
|
||||
|
||||
5.RDF_Error RDF_DisposeCursor (RDF_Cursor c);
|
||||
When you are done with a cursor, call this function. Remember to free your pdata before calling this.
|
||||
*/
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
import java.util.Vector;
|
||||
import java.util.Enumeration;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public class AC_Attribute implements IAttribute {
|
||||
private String fName;
|
||||
private Vector fValues;
|
||||
|
||||
/** Create an attribute with mutliple values.
|
||||
*/
|
||||
public AC_Attribute (String aName, String[] aValues) {
|
||||
fName = aName;
|
||||
fValues = new Vector();
|
||||
|
||||
if (null != aValues) {
|
||||
for (int i = 0; i < aValues.length; i++) {
|
||||
if (null != aValues[i])
|
||||
add(aValues[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Create an attribute with one value.
|
||||
*/
|
||||
public AC_Attribute (String aName, String aValue) {
|
||||
fName = aName;
|
||||
fValues = new Vector();
|
||||
|
||||
if (null != aValue)
|
||||
add(aValue);
|
||||
}
|
||||
|
||||
/** Create an attribute with no values.
|
||||
*/
|
||||
public AC_Attribute (String aName) {
|
||||
fName = aName;
|
||||
fValues = new Vector();
|
||||
}
|
||||
|
||||
/** Add an value to this attribute
|
||||
*/
|
||||
public void add (String aValue) {
|
||||
fValues.addElement (aValue);
|
||||
}
|
||||
|
||||
/** Return the name of this attribute.
|
||||
*/
|
||||
public String getName() {
|
||||
return fName;
|
||||
}
|
||||
|
||||
/** Return the first string value of this attribute.
|
||||
*/
|
||||
public String getValue () {
|
||||
return (String) fValues.elementAt(0);
|
||||
}
|
||||
|
||||
/** Return the string values of this attribute.
|
||||
*/
|
||||
public Enumeration getStringValues () {
|
||||
return fValues.elements();
|
||||
}
|
||||
|
||||
/** Has the attribute new to the parent?
|
||||
*/
|
||||
public boolean isNew() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Has the attribute been deleted since the last update with it's parent.
|
||||
*/
|
||||
public boolean isDeleted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Has the attribute been modified since the last update with it's parent.
|
||||
*/
|
||||
public boolean isModified() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public class AC_Exception extends Exception {
|
||||
public AC_Exception () {
|
||||
super ();
|
||||
}
|
||||
|
||||
public AC_Exception (String anExplaination) {
|
||||
super (anExplaination);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public class AC_ID {
|
||||
AC_ID () {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public class AC_IDSet extends Vector {
|
||||
public final static int ASCENDING = 0;
|
||||
public final static int DESCENDING = 1;
|
||||
|
||||
/** Default constructor
|
||||
*/
|
||||
public AC_IDSet () {
|
||||
}
|
||||
|
||||
/** Copy constructor
|
||||
*/
|
||||
public AC_IDSet (AC_IDSet anIDSet) {
|
||||
}
|
||||
|
||||
public void addSet (AC_IDSet aSet) {
|
||||
}
|
||||
|
||||
public void sort(int aDirection) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public interface IAttribute {
|
||||
/** Return the name of this attribute.
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/** Return the first string value of this attribute.
|
||||
*/
|
||||
public String getValue ();
|
||||
|
||||
/** Has the attribute new to the parent?
|
||||
*/
|
||||
public boolean isNew();
|
||||
|
||||
/** Has the attribute been deleted since the last update with it's parent.
|
||||
*/
|
||||
public boolean isDeleted();
|
||||
|
||||
/** Has the attribute been modified since the last update with it's parent.
|
||||
*/
|
||||
public boolean isModified();
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public interface IAttributeSet {
|
||||
/** Add an attrbiute to the set.
|
||||
*/
|
||||
// public void add(AC_Attribute anAttribute) {
|
||||
|
||||
/** Return the card set enumeration.
|
||||
*/
|
||||
public Enumeration getEnumeration();
|
||||
|
||||
/** Only intended to be accessed by LDAP_AttributeSetEnumeration.
|
||||
*/
|
||||
// public boolean hasMoreElements();
|
||||
|
||||
/** Only intended to be accessed by LDAP_AttributeSetEnumeration.
|
||||
*/
|
||||
// public Object nextElement();
|
||||
|
||||
/** Return the named attribute.
|
||||
*/
|
||||
public IAttribute getAttribute(String anAttributeName);
|
||||
|
||||
/** Return the number of attributes in the set.
|
||||
*/
|
||||
public int size();
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public interface ICard {
|
||||
/** Return the parent card source from where this card came from (if any)
|
||||
*/
|
||||
public ICardSource getParent();
|
||||
|
||||
/** Add an attribute to the card.
|
||||
*/
|
||||
public void addAttribute (IAttribute anAttribute);
|
||||
|
||||
/** Get a value of the address card.
|
||||
*/
|
||||
public IAttribute getAttribute (String anAttributeName);
|
||||
|
||||
/** Get the full attribute set for this card.
|
||||
*/
|
||||
public IAttributeSet getAttributeSet ();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public interface ICardSet {
|
||||
|
||||
/** Add a card to the set.
|
||||
*/
|
||||
public void add (ICard aCard);
|
||||
|
||||
/** Remove a card from the set.
|
||||
* This only removes the card from the set NOT the source of the set.
|
||||
*/
|
||||
public void remove (ICard aCard);
|
||||
|
||||
/** Sort the set.
|
||||
*/
|
||||
public void sort(String [] anAttributeArray);
|
||||
|
||||
/** Return the card set enumeration.
|
||||
*/
|
||||
public Enumeration getEnumeration();
|
||||
|
||||
/** Only intended to be accessed by LDAP_SetEnumeration.
|
||||
*/
|
||||
// public boolean hasMoreElements();
|
||||
|
||||
/** Only intended to be accessed by LDAP_SetEnumeration.
|
||||
*/
|
||||
// public Object nextElement();
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public interface ICardSource {
|
||||
/**
|
||||
* closing the source
|
||||
*/
|
||||
public void close ();
|
||||
|
||||
/**
|
||||
* replication
|
||||
* Update this address card source
|
||||
*/
|
||||
// public void update (ICardSource aSourceOfChangedCards);
|
||||
|
||||
/**
|
||||
* retrieveing address cards
|
||||
*/
|
||||
// public Enumeration getCardEnumeration (Term QueryTerm, String[] AttributesArray);
|
||||
public ICardSet getCardSet (ITerm QueryTerm, String[] AttributesArray);
|
||||
// public void getCardSink (Term QueryTerm, String[] AttributesArray, AC_Sink aCardSink);
|
||||
|
||||
/** add a card(s)
|
||||
*/
|
||||
public void add (ICard aCard) throws AC_Exception;
|
||||
// public void add (AC_Set aCardSet) throws AC_Exception;
|
||||
|
||||
/** update a card(s)
|
||||
*/
|
||||
public void update (ICard aCard) throws AC_Exception;
|
||||
// public void update (AC_Set aCardSet) throws AC_Exception;
|
||||
|
||||
/** delete a card(s)
|
||||
*/
|
||||
public void delete (ICard aCard) throws AC_Exception;
|
||||
// public void delete (AC_Set aCardSet) throws AC_Exception;
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
public interface IQuerySet {
|
||||
public AC_IDSet opEqual (IAttribute ACA);
|
||||
public AC_IDSet opNotEqual (IAttribute ACA);
|
||||
// public ACIDSet opGreaterThan (AC_Attribute ACA);
|
||||
// public ACIDSet opGreaterThanOrEqual (AC_Attribute ACA);
|
||||
// public ACIDSet opLessThan (AC_Attribute ACA);
|
||||
// public ACIDSet opLessThanOrEqual (AC_Attribute ACA);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
public interface IQueryString {
|
||||
public String opAnd (ITerm aLeftTerm, ITerm aRightTerm);
|
||||
public String opOr (ITerm aLeftTerm, ITerm aRightTerm);
|
||||
public String opEqual (IAttribute ACA);
|
||||
public String opNotEqual (IAttribute ACA);
|
||||
public String opGTE (IAttribute ACA);
|
||||
public String opLTE (IAttribute ACA);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
import grendel.storage.intertwingle.*;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public interface ITerm {
|
||||
public String getExpression(IQueryString iqs);
|
||||
public AC_IDSet getSet (IQuerySet iqs);
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
import netscape.ldap.*;
|
||||
import java.util.Enumeration;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public class LDAP_Attribute implements IAttribute {
|
||||
private LDAPAttribute fMyAttribute;
|
||||
|
||||
protected LDAP_Attribute (LDAPAttribute anAttribute) {
|
||||
fMyAttribute = anAttribute;
|
||||
}
|
||||
|
||||
/** Return the name of this attribute.
|
||||
*/
|
||||
public String getName() {
|
||||
return fMyAttribute.getName();
|
||||
}
|
||||
|
||||
/** Return the first string value of this attribute.
|
||||
*/
|
||||
public String getValue () {
|
||||
// Get only the first value (handle multiple values later).
|
||||
Enumeration enumVals = fMyAttribute.getStringValues();
|
||||
if ( enumVals.hasMoreElements() ) {
|
||||
return (String) enumVals.nextElement();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Has the attribute new to the parent?
|
||||
*/
|
||||
public boolean isNew() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Has the attribute been deleted since the last update with it's parent.
|
||||
*/
|
||||
public boolean isDeleted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Has the attribute been modified since the last update with it's parent.
|
||||
*/
|
||||
public boolean isModified() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
import netscape.ldap.*;
|
||||
import java.util.Enumeration;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public class LDAP_AttributeSet implements IAttributeSet, Enumeration {
|
||||
private LDAPAttributeSet fMyAttributeSet;
|
||||
private Enumeration fAttrEnum;
|
||||
|
||||
/** Create a new emtpy AttributeSet
|
||||
*/
|
||||
protected LDAP_AttributeSet (LDAPAttributeSet aSet) {
|
||||
fMyAttributeSet = aSet;
|
||||
}
|
||||
|
||||
/** Add an attrbiute to the set.
|
||||
*/
|
||||
// public void add(AC_Attribute anAttribute) {
|
||||
// fSet.put (anAttribute.getName(), anAttribute.getValue());
|
||||
// }
|
||||
|
||||
/** Return the named attribute.
|
||||
*/
|
||||
public IAttribute getAttribute(String anAttributeName) {
|
||||
return new LDAP_Attribute (fMyAttributeSet.getAttribute(anAttributeName));
|
||||
}
|
||||
|
||||
/** Return the number of attributes in the set.
|
||||
*/
|
||||
public int size() {
|
||||
return fMyAttributeSet.size();
|
||||
}
|
||||
|
||||
/** Return the attribute set enumeration.
|
||||
* We enumerate our own attribute set.
|
||||
*/
|
||||
public Enumeration getEnumeration() {
|
||||
//FIX: Not multi-threaded!
|
||||
//initiailize the enumeration cursor.
|
||||
fAttrEnum = fMyAttributeSet.getAttributes();
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Enumeration methods
|
||||
*/
|
||||
public boolean hasMoreElements() {
|
||||
return fAttrEnum.hasMoreElements();
|
||||
}
|
||||
|
||||
/** Enumeration methods
|
||||
*/
|
||||
public Object nextElement() {
|
||||
//get the next attribute.
|
||||
LDAPAttribute attr = (LDAPAttribute) fAttrEnum.nextElement();
|
||||
|
||||
//cache the element.
|
||||
// fMyElementCache.add (card);
|
||||
|
||||
//return the LDAPAttribute rapped in a IAttribute.
|
||||
return new LDAP_Attribute (attr);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
import netscape.ldap.*;
|
||||
import java.util.Enumeration;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public class LDAP_Card implements ICard {
|
||||
private LDAP_Server fParentSource;
|
||||
private LDAPEntry fMyEntry;
|
||||
|
||||
/** Constructor for LDAP server.
|
||||
*/
|
||||
protected LDAP_Card(LDAP_Server aParentSource, LDAPEntry anEntry) {
|
||||
fParentSource = aParentSource;
|
||||
fMyEntry = anEntry;
|
||||
}
|
||||
|
||||
/** Return the parent card source from where this card came from (if any)
|
||||
*/
|
||||
public ICardSource getParent() {
|
||||
return fParentSource;
|
||||
}
|
||||
|
||||
/** Add an attribute to the card.
|
||||
* FIX (this updates the server!)
|
||||
*/
|
||||
public void addAttribute (IAttribute anAttribute) {
|
||||
//get the native attribute set.
|
||||
// LDAPAttributeSet nativeAttrSet = fMyEntry.getAttributeSet();
|
||||
|
||||
//convert the local attribute into a native LDAP attribute and add.
|
||||
// nativeAttrSet.add(localAttr.getLDAPAttribute());
|
||||
}
|
||||
|
||||
/** Get a value of the address card.
|
||||
*/
|
||||
public IAttribute getAttribute (String anAttributeName) {
|
||||
return new LDAP_Attribute (fMyEntry.getAttribute(anAttributeName));
|
||||
}
|
||||
|
||||
/** Get the full attribute set for this card.
|
||||
*/
|
||||
public IAttributeSet getAttributeSet () {
|
||||
return new LDAP_AttributeSet (fMyEntry.getAttributeSet());
|
||||
}
|
||||
|
||||
//LDAP specific methods:
|
||||
|
||||
/** Rerturn the DN
|
||||
*/
|
||||
public String getDN() {
|
||||
return fMyEntry.getDN();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
import netscape.ldap.*;
|
||||
import java.util.Enumeration;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public class LDAP_CardSet implements ICardSet, Enumeration {
|
||||
private LDAP_Server fParentSource;
|
||||
private LDAPSearchResults fResultSet;
|
||||
|
||||
/** Constructor for LDAP server.
|
||||
*/
|
||||
protected LDAP_CardSet (LDAP_Server aParentSource, LDAPSearchResults aResultSet) {
|
||||
fParentSource = aParentSource;
|
||||
fResultSet = aResultSet;
|
||||
}
|
||||
|
||||
/** Add a card to the set.
|
||||
* This only addes the card to the set NOT the source of the set.
|
||||
*/
|
||||
public void add (ICard aCard) {
|
||||
// fCardList.addElement (aCard);
|
||||
}
|
||||
|
||||
/** Remove a card from the set.
|
||||
* This only removes the card from the set NOT the source of the set.
|
||||
*/
|
||||
public void remove (ICard aCard) {
|
||||
}
|
||||
|
||||
/** Sort the set.
|
||||
*/
|
||||
public synchronized void sort(String [] sortAttrs) {
|
||||
boolean[] ascending = {true, true};
|
||||
fResultSet.sort(new LDAPCompareAttrNames(sortAttrs, ascending));
|
||||
}
|
||||
|
||||
/** Return the card set enumeration.
|
||||
* We enumerate our own cards.
|
||||
* FIX: Not multi-threaded!
|
||||
*/
|
||||
public Enumeration getEnumeration() {
|
||||
//initiailize the enumeration cursor.
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Enumeration methods
|
||||
*/
|
||||
public boolean hasMoreElements() {
|
||||
return fResultSet.hasMoreElements();
|
||||
}
|
||||
|
||||
/** Enumeration methods
|
||||
*/
|
||||
public Object nextElement() {
|
||||
//return the next LDAPentry as an LDAP_Card.
|
||||
LDAPEntry entry = (LDAPEntry) fResultSet.nextElement();
|
||||
|
||||
//cache the element.
|
||||
// fMyElementCache.add (entry);
|
||||
|
||||
//return the LDAPEntry rapped in an ICard interface.
|
||||
return new LDAP_Card (fParentSource, entry);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,275 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
import netscape.ldap.*;
|
||||
import java.util.*;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public class LDAP_Server implements ICardSource, IQueryString {
|
||||
LDAPConnection fConnection;
|
||||
|
||||
public LDAP_Server (String ServerName) {
|
||||
this (ServerName, 389, "", "");
|
||||
}
|
||||
|
||||
public LDAP_Server (String aServerName, int aPort, String aUserName, String aPassword) {
|
||||
try {
|
||||
// Connect to server.
|
||||
fConnection = new LDAPConnection();
|
||||
fConnection.connect (aServerName, aPort);
|
||||
|
||||
// authenticate to the directory as nobody.
|
||||
//fConnection.authenticate( aUserName, aPassword );
|
||||
} catch( LDAPException e ) {
|
||||
System.out.println( "Error: " + e.toString() );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** Close the addres card source
|
||||
*/
|
||||
public void close () {
|
||||
}
|
||||
|
||||
private final static String LEFT_PAREN = "(";
|
||||
private final static String RIGHT_PARAN = ")";
|
||||
|
||||
private String escape (String aStringToEscape) {
|
||||
String escapeChars = LEFT_PAREN + RIGHT_PARAN + "*";
|
||||
//FIX
|
||||
return aStringToEscape;
|
||||
}
|
||||
|
||||
public String opAnd (ITerm aLeftTerm, ITerm aRightTerm) {
|
||||
return LEFT_PAREN + "&" + aLeftTerm.getExpression (this) + aRightTerm.getExpression (this) + RIGHT_PARAN;
|
||||
}
|
||||
|
||||
public String opOr (ITerm aLeftTerm, ITerm aRightTerm) {
|
||||
return LEFT_PAREN + "|" + aLeftTerm.getExpression (this) + aRightTerm.getExpression (this) + RIGHT_PARAN;
|
||||
}
|
||||
|
||||
public String opEqual (IAttribute ACA) {
|
||||
return LEFT_PAREN + ACA.getName() + "=" + escape (ACA.getValue ()) + RIGHT_PARAN;
|
||||
}
|
||||
|
||||
public String opNotEqual (IAttribute ACA) {
|
||||
return LEFT_PAREN + "!" + opEqual (ACA) + RIGHT_PARAN;
|
||||
}
|
||||
|
||||
public String opGTE (IAttribute ACA) {
|
||||
return LEFT_PAREN + ACA.getName() + ">=" + escape (ACA.getValue ()) + RIGHT_PARAN;
|
||||
}
|
||||
|
||||
public String opLTE (IAttribute ACA) {
|
||||
return LEFT_PAREN + ACA.getName() + "<=" + escape (ACA.getValue ()) + RIGHT_PARAN;
|
||||
}
|
||||
|
||||
|
||||
/** Retrieveing address cards as a set.
|
||||
*/
|
||||
public ICardSet getCardSet (ITerm aQueryTerm, String[] anAttributesArray) {
|
||||
final String COMMON_NAME_ID = "cn";
|
||||
final String ORGANIZATION_ID = "o";
|
||||
final String COUNTRY_ID = "c";
|
||||
final String SIR_NAME_ID = "sn";
|
||||
final String MAIL_ID = "mail";
|
||||
|
||||
LDAPSearchResults queryResults = null;
|
||||
|
||||
try {
|
||||
String filter = aQueryTerm.getExpression(this);
|
||||
String searchBase = COUNTRY_ID + "=" + "US";
|
||||
|
||||
LDAPSearchConstraints cons = fConnection.getSearchConstraints();
|
||||
cons.setBatchSize( 1 );
|
||||
|
||||
queryResults = fConnection.search( searchBase,
|
||||
LDAPConnection.SCOPE_ONE,
|
||||
filter,
|
||||
anAttributesArray,
|
||||
false,
|
||||
cons);
|
||||
}
|
||||
catch( LDAPException e ) {
|
||||
System.out.println( "Error: " + e.toString() );
|
||||
}
|
||||
|
||||
return new LDAP_CardSet (this, queryResults);
|
||||
}
|
||||
|
||||
|
||||
/** Add an entry to the server.
|
||||
*/
|
||||
public void add (ICard aCard) throws AC_Exception {
|
||||
//get all attributes for this card as a set
|
||||
IAttributeSet AC_attrSet = aCard.getAttributeSet (); //From AddressCard
|
||||
LDAPAttributeSet LDAP_attrSet = new LDAPAttributeSet(); //To LDAP
|
||||
|
||||
//enumerate thru each attribute and translate from CA attributes into LDAP attributes.
|
||||
for (Enumeration enum = AC_attrSet.getEnumeration(); enum.hasMoreElements() ;) {
|
||||
|
||||
//Get the old
|
||||
IAttribute AC_attr = (IAttribute) enum.nextElement();
|
||||
//Create the new
|
||||
LDAPAttribute LDAP_attr = new LDAPAttribute(AC_attr.getName(), AC_attr.getValue());
|
||||
|
||||
//add the attribute to the LDAP set.
|
||||
LDAP_attrSet.add( LDAP_attr );
|
||||
}
|
||||
|
||||
try {
|
||||
//FIX!!!
|
||||
//create a new enry for the LDAP server
|
||||
String dn = "cn=Barbara Jensen,ou=Product Development,o=Ace Industry,c=US";
|
||||
LDAPEntry anEntry = new LDAPEntry( dn, LDAP_attrSet );
|
||||
|
||||
//*** ADD THE ENTRY ***
|
||||
fConnection.add( anEntry );
|
||||
|
||||
} catch (LDAPException le) {
|
||||
//FIX
|
||||
throw new AC_Exception ("Couldn't add card to server.");
|
||||
}
|
||||
}
|
||||
|
||||
/** Delete an entry from the server.
|
||||
*/
|
||||
public LDAP_Card checkMyCard (ICard aCard) throws AC_Exception {
|
||||
//check that the etnry came from an LDAP server.
|
||||
if (aCard instanceof LDAP_Card) {
|
||||
LDAP_Card card = (LDAP_Card) aCard;
|
||||
|
||||
//check that the entry can from this LDAP server.
|
||||
if (this == card.getParent ()) {
|
||||
|
||||
//everthing's fine so return the card.
|
||||
return card;
|
||||
}
|
||||
else {
|
||||
throw new AC_Exception ("Not from this server.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new AC_Exception ("Not from an LDAP server.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Delete an entry from the server.
|
||||
*/
|
||||
public void delete (ICard aCard) throws AC_Exception {
|
||||
try {
|
||||
//make sure the card came from this server.
|
||||
LDAP_Card card = checkMyCard(aCard); //throws AC_Exception.
|
||||
|
||||
//FIX
|
||||
//?? What can still LOCALY happen to the card after it's deleted from the LDPA server??
|
||||
try {
|
||||
//*** DELETE THE ENTRY ***
|
||||
fConnection.delete ( card.getDN() );
|
||||
} catch (LDAPException le) {
|
||||
//FIX
|
||||
throw new AC_Exception ("Couldn't delete card from server.");
|
||||
}
|
||||
}
|
||||
//BAD card. The card didn't come from this server.
|
||||
catch (AC_Exception ace) {
|
||||
//rethrow the exception
|
||||
throw ace;
|
||||
}
|
||||
}
|
||||
|
||||
/** Update an entries attributes on the server.
|
||||
*/
|
||||
public void update (ICard aCard) throws AC_Exception {
|
||||
try {
|
||||
//make sure the card came from this server.
|
||||
LDAP_Card card = checkMyCard(aCard); //throws AC_Exception.
|
||||
|
||||
//Ok, the card came from us so lets try to update the server.
|
||||
//Get the set of attributes that have changed.
|
||||
IAttributeSet AC_attrSet = card.getAttributeSet ();
|
||||
|
||||
//Create a modifcation set to provide to the LDAP server.
|
||||
LDAPModificationSet LDAP_modSet = new LDAPModificationSet();
|
||||
|
||||
//enumerate thru each attribute
|
||||
for (Enumeration enum = AC_attrSet.getEnumeration() ; enum.hasMoreElements() ;) {
|
||||
IAttribute AC_attr = (IAttribute) enum.nextElement();
|
||||
int LDAP_mod = 0;
|
||||
boolean attributeModified = false;
|
||||
|
||||
//Has the attribute been added?
|
||||
if (true == AC_attr.isNew ()) {
|
||||
LDAP_mod = LDAPModification.ADD;
|
||||
attributeModified = true;
|
||||
}
|
||||
//Has the attribute been deleted?
|
||||
else if (true == AC_attr.isDeleted ()) {
|
||||
LDAP_mod = LDAPModification.DELETE;
|
||||
attributeModified = true;
|
||||
}
|
||||
//Has the attribute been changed?
|
||||
else if (true == AC_attr.isModified ()) {
|
||||
LDAP_mod = LDAPModification.REPLACE;
|
||||
attributeModified = true;
|
||||
}
|
||||
|
||||
//if modified then add to mod set.
|
||||
if (true == attributeModified) {
|
||||
LDAPAttribute LDAP_attr = new LDAPAttribute(AC_attr.getName(), AC_attr.getValue());
|
||||
LDAP_modSet.add (LDAP_mod, LDAP_attr);
|
||||
}
|
||||
}
|
||||
|
||||
//Did we get any modifcations to send to the server?
|
||||
if (0 < LDAP_modSet.size()) {
|
||||
//submit the modifcation set to the server
|
||||
try {
|
||||
|
||||
//*** MODIFY THE ENTRY ***
|
||||
fConnection.modify (card.getDN(), LDAP_modSet);
|
||||
|
||||
} catch (LDAPException le) {
|
||||
//FIX
|
||||
throw new AC_Exception ("Couldn't update server.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//BAD card. The card didn't come from this server.
|
||||
catch (AC_Exception ace) {
|
||||
//rethrow the exception
|
||||
throw ace;
|
||||
}
|
||||
// //else the card didn't come from this server so throw excpetion
|
||||
// else {
|
||||
// //FIX
|
||||
// //Need to consider weather is ok for a card from one connection to update
|
||||
// //to another connection of both connections are talking to the same server.
|
||||
// throw new AC_Exception ("Address Card didn't originate from this connection.");
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License
|
||||
# Version 1.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.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
# the License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Grendel mail/news client.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
SRCS= \
|
||||
ACS_Personal.java \
|
||||
AC_Attribute.java \
|
||||
AC_Exception.java \
|
||||
AC_ID.java \
|
||||
AC_IDSet.java \
|
||||
IAttribute.java \
|
||||
IAttributeSet.java \
|
||||
ICard.java \
|
||||
ICardSet.java \
|
||||
ICardSource.java \
|
||||
IQuerySet.java \
|
||||
IQueryString.java \
|
||||
ITerm.java \
|
||||
LDAP_Attribute.java \
|
||||
LDAP_AttributeSet.java \
|
||||
LDAP_Card.java \
|
||||
LDAP_CardSet.java \
|
||||
LDAP_Server.java \
|
||||
SelfTest.java \
|
||||
TermAnd.java \
|
||||
TermEqual.java \
|
||||
TermNotEqual.java \
|
||||
TermOr.java \
|
||||
$(NULL)
|
||||
|
||||
include ../../rules.mk
|
|
@ -0,0 +1,500 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
public class SelfTest {
|
||||
public SelfTest () {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////
|
||||
//example #0
|
||||
//List all cards and their attributes.
|
||||
public static void main(String argv[]) {
|
||||
//open the LDAP address card source ldap.infospace.com
|
||||
ICardSource Four11AddressBook = new LDAP_Server ("ldap.whowhere.com");
|
||||
|
||||
//define the card query.
|
||||
ITerm query = new TermEqual (new AC_Attribute ("sn", "Lester"));
|
||||
|
||||
//Define the attributes to return
|
||||
String[] attributes = {"sn", "cn", "o", "mail", "city"};
|
||||
|
||||
//query the LDAP server.
|
||||
ICardSet cardSet = Four11AddressBook.getCardSet (query, attributes);
|
||||
|
||||
//Sort the list.
|
||||
String[] sortOrder = {"sn", "mail"};
|
||||
cardSet.sort (sortOrder);
|
||||
|
||||
//Enumerate thru the cards.
|
||||
for (Enumeration cardEnum = cardSet.getEnumeration(); cardEnum.hasMoreElements(); ) {
|
||||
ICard card = (ICard) cardEnum.nextElement();
|
||||
|
||||
System.out.println ("==== Card ====");
|
||||
IAttributeSet attrSet = card.getAttributeSet ();
|
||||
|
||||
//Enumerate thru the attributes.
|
||||
for (Enumeration attEnum = attrSet.getEnumeration(); attEnum.hasMoreElements(); ) {
|
||||
IAttribute attr = (IAttribute) attEnum.nextElement();
|
||||
|
||||
System.out.println ("Attr: " + attr.getName() + " = " + attr.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
//AC_Sources close when they fall out of scope.
|
||||
// LDAP_Server.close ();
|
||||
}
|
||||
|
||||
/*
|
||||
//example #1
|
||||
//Tranfering card from LDAP server to local address book using an "AddressSet".
|
||||
public static void main(String argv[]) {
|
||||
//open the LDAP address card source
|
||||
IAC_Source Four11AddressBook = new LDAP_Server ("ldap.whowhere.com");
|
||||
// IAC_Source Four11AddressBook = new LDAP_Server ("lpad.four11.com", "lesters", "SecretPassword");
|
||||
|
||||
//Create the search
|
||||
FullName
|
||||
|
||||
NickName
|
||||
FirstName
|
||||
MiddleName
|
||||
LastName
|
||||
Organization
|
||||
Locality
|
||||
Region
|
||||
EmailAddress
|
||||
Comment
|
||||
HTMLMail
|
||||
Title
|
||||
PostOfficeBox
|
||||
Address
|
||||
ZipCode
|
||||
Country
|
||||
WorkPhone
|
||||
HomePhone
|
||||
FaxPhone
|
||||
ConferenceAddress
|
||||
ConferenceServer
|
||||
DistinguishedName
|
||||
|
||||
TermEqual (AC_Attribute);
|
||||
TermNotEqual (AC_Attribute);
|
||||
TermGreaterThan (AC_Attribute);
|
||||
TermGreaterThanOrEqual (AC_Attribute);
|
||||
TermLessThan (AC_Attribute);
|
||||
TermLessThanOrEqual (AC_Attribute);
|
||||
|
||||
// AB.Search.Term query = new TermOr ( new AC_Attribute ("givenname", "Lester"),
|
||||
// new AC_Attribute ("xmozillanickname", "Les"));
|
||||
|
||||
ITerm query = new TermEqual (new AC_Attribute ("sn", "Lester"));
|
||||
|
||||
//Define the attributes to return
|
||||
// String[] attributes = {"givenname", "surname", "o", "mail"};
|
||||
String[] attributes = {"cn", "o", "mail"};
|
||||
String[] sortOrder = {"givenname", "surname"};
|
||||
|
||||
//query the LDAP server.
|
||||
AC_Set cardSet = Four11AddressBook.getCardSet (query, attributes);
|
||||
|
||||
//Sort the list.
|
||||
cardSet.sort (sortOrder);
|
||||
|
||||
//print the list of cards and their attributes.
|
||||
for (Enumeration cardEnum = cardSet.getCardEnumeration(); cardEnum.hasMoreElements(); ) {
|
||||
AC card = (AC) cardEnum.nextElement();
|
||||
|
||||
System.out.println ("==== Card ====");
|
||||
AC_AttributeSet attrSet = card.getAttributeSet ();
|
||||
|
||||
for (Enumeration attEnum = attrSet.elements(); attEnum.hasMoreElements(); ) {
|
||||
AC_Attribute attr = (AC_Attribute) attEnum.nextElement();
|
||||
|
||||
System.out.println ("Attr: Name = " + attr.getName() + " Value = " + attr.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
//open the local address card source
|
||||
// (true = create if needed)
|
||||
ACS_Personal myLocalAddressBook = new ACS_Personal ("MyAddressBook.nab", true);
|
||||
|
||||
//copy over the address cards
|
||||
// true = overwrite if collision)
|
||||
myLocalAddressBook.add (cardSet, true);
|
||||
|
||||
//AC_Sources close when they fall out of scope.
|
||||
myLocalAddressBook.close ();
|
||||
}
|
||||
|
||||
//example #2
|
||||
//Transfer cards from LDAP server to local address book using enumeration.
|
||||
main () {
|
||||
//open the LDAP address card source
|
||||
AC_Source Four11AddressBook = new LDAPServer ("lpad.four11.com", "lesters", "SecretPassword");
|
||||
|
||||
//Create the search
|
||||
AB.Search.Term query = new TermOr ( new AC_Attribute ("givenname", "Lester"),
|
||||
new AC_Attribute ("xmozillanickname", "Les"));
|
||||
|
||||
//Define the attributes to return
|
||||
String[] attributes = {"givenname", "surname", "o", "mail"};
|
||||
|
||||
//open the local address card source
|
||||
// (true = create if needed)
|
||||
AC_Source myLocalAddressBook = new LocalStore ("MyAddressBook.nab", true);
|
||||
|
||||
//query the LDAP server.
|
||||
for (Enumeration enum = Four11AddressBook.getCardEnumeration (query, attributes); enum.hasMoreElements() ;) {
|
||||
AC card = (AC_) enum.nextElement();
|
||||
|
||||
//only copy the netscape people.
|
||||
if (true == card.getAttribute ("o").getValue().equals ("Netscape")) {
|
||||
// true = overwrite if collision)
|
||||
myLocalAddressBook.add (card, true);
|
||||
}
|
||||
}
|
||||
|
||||
//AC_Sources close when they fall out of scope.
|
||||
}
|
||||
|
||||
|
||||
//example #3
|
||||
//Transfer cards from LDAP server to local address book using an "AddressList" and enumeration.
|
||||
main () {
|
||||
//open the LDAP address card source
|
||||
AC_Source Four11AddressBook = new LDAPServer ("lpad.four11.com", "lesters", "SecretPassword");
|
||||
|
||||
//Create the search
|
||||
AB.Search.Term query = new OrTerm ( new AC_Attribute ("givenname", "Lester"),
|
||||
new AC_Attribute ("xmozillanickname", "Les"));
|
||||
|
||||
//Define the attributes to return
|
||||
String[] attributes = {"givenname", "surname", "o", "mail"};
|
||||
String[] sortOrder = {"givenname", "surname"};
|
||||
|
||||
//query the LDAP server.
|
||||
AC_Set cardSet = Four11AddressBook.getCardSet (query, attributes);
|
||||
|
||||
//Sort the list.
|
||||
cardSet.sort (sortOrder);
|
||||
|
||||
//open the local address card source
|
||||
// (true = create if needed)
|
||||
AC_Source myLocalAddressBook = new LocalStore ("MyAddressBook.nab", true);
|
||||
|
||||
//Step thru the card list.
|
||||
for (Enumeration enum = cardSet.getCardEnumeration (); enum.hasMoreElements() ;) {
|
||||
AC card = (AC) enum.nextElement();
|
||||
|
||||
//only copy netscape people.
|
||||
if (true == card.getAttribute ("o").equals ("Netscape")) {
|
||||
// true = overwrite if collision)
|
||||
myLocalAddressBook.add (card, true);
|
||||
}
|
||||
}
|
||||
|
||||
//AC_Sources close when they fall out of scope.
|
||||
}
|
||||
|
||||
//example #4
|
||||
//Deleting card from the local addres book
|
||||
main () {
|
||||
//open the local address card source
|
||||
// (false = fail if not already created)
|
||||
AC_Source myLocalAddressBook = new LocalStore ("MyAddressBook.nab", false);
|
||||
|
||||
AB.Search.Term query = new AC_Attribute ("givenname", "Lester");
|
||||
|
||||
//query the AC_Source
|
||||
AC_Set cardSet = myLocalAddressBook.getCardSet (query);
|
||||
|
||||
//delete the cards
|
||||
myLocalAddressBook.delete(cardSet);
|
||||
|
||||
//AC_Sources close when they fall out of scope.
|
||||
}
|
||||
|
||||
|
||||
//example #5
|
||||
//Tranfering card from LDAP server to local address book using enumeration and collision detection.
|
||||
main () {
|
||||
//open the LDAP address card source
|
||||
AC_Source Four11AddressBook = new LDAPServer ("lpad.four11.com", "lesters", "SecretPassword");
|
||||
|
||||
//Create the search
|
||||
AB.Search.Term query = new AC_Attribute ("givenname", "Lester");
|
||||
|
||||
//open the local address card source
|
||||
// (true = create if needed)
|
||||
AC_Source myLocalAddressBook = new LocalStore ("MyAddressBook.nab", true);
|
||||
|
||||
//query the LDAP server.
|
||||
for (Enumeration enum = Four11AddressBook.getCardEnumeration (query, attributes); enum.hasMoreElements() ;) {
|
||||
try {
|
||||
// false = throw exception if collision
|
||||
myLocalAddressBook.add ((AC_) enum.nextElement(), false);
|
||||
|
||||
// Alternate form (test the set).
|
||||
// if (false == myLocalAddressBook.willOverwrite ((AC_) enum.nextElement())) {
|
||||
// myLocalAddressBook.add ((AC_) enum.nextElement(). false);
|
||||
// }
|
||||
|
||||
} catch (CardOverwriteException coe) {
|
||||
}
|
||||
}
|
||||
|
||||
//AC_Sources close when they fall out of scope.
|
||||
}
|
||||
|
||||
//example #6
|
||||
//Find all the attributes of a card source?
|
||||
main () {
|
||||
//open the LDAP address card source
|
||||
AC_Source Four11AddressBook = new LDAPServer ("lpad.four11.com", "lesters", "SecretPassword");
|
||||
|
||||
AC_AttributeSet attrs = Four11AddressBook.getAttributeSet();
|
||||
|
||||
for (Enumeration enumAttrs = attrs.getAttributes(); ; enumAttrs.hasMoreElements() ;) {
|
||||
AC_Attribute anAttr = (AC_Attribute) enumAttrs.nextElement();
|
||||
|
||||
System.out.println( "Attribute Name: " + anAttr.getName() );
|
||||
}
|
||||
|
||||
//AC_Sources close when they fall out of scope.
|
||||
}
|
||||
|
||||
//example #7
|
||||
//Update the two address books
|
||||
main () {
|
||||
//open the LDAP address card source
|
||||
AC_Source Four11AddressBook = new LDAPServer ("lpad.four11.com", "lesters", "SecretPassword");
|
||||
|
||||
//open the local address card source
|
||||
AC_Source myLocalAddressBook = new LocalStore ("MyAddressBook.nab", true);
|
||||
|
||||
//update the local address book from the LDAp server.
|
||||
myLocalAddressBook.update (Four11AddressBook);
|
||||
|
||||
//update the LDAP server from the local address book.
|
||||
Four11AddressBook.update (myLocalAddressBook);
|
||||
|
||||
//AC_Sources close when they fall out of scope.
|
||||
}
|
||||
|
||||
//example #8
|
||||
//Transfer cards from serveral LDAP servers to local address book using an "AddressSet".
|
||||
main () {
|
||||
//open the LDAP address card source
|
||||
AC_SourceSet lpadServers = new AC_SourceSet();
|
||||
|
||||
//add the LDAP servers to the set. Order is important.
|
||||
lpadServers.add (new LDAPServer ("lpad.four11.com", "lesters", "SecretPassword"));
|
||||
lpadServers.add (new LDAPServer ("lpad.infoseek.com", null, null));
|
||||
|
||||
//get all cards that have a department of "k8040" or "K8050".
|
||||
Term query = new AC_Attribute ("xdepartment", {"k8040", "k8050"});
|
||||
|
||||
//Define the attributes to return
|
||||
String[] attributes = {"givenname", "surname", "o", "mail", "xdepartment"};
|
||||
|
||||
//query the LDAP servers.
|
||||
AC_Set cardSet = lpadServers.getCardSet (query, attributes);
|
||||
|
||||
//open the local address card source
|
||||
// (true = create if needed)
|
||||
AC_Source myLocalAddressBook = new LocalStore ("MyAddressBook.nab", true);
|
||||
|
||||
//copy over the address cards
|
||||
// true = overwrite if collision)
|
||||
myLocalAddressBook.add (cardSet, true);
|
||||
|
||||
//AC_Sources close when they fall out of scope.
|
||||
}
|
||||
|
||||
|
||||
//example #9
|
||||
//Add a new card to the local address book then change it then delete it.
|
||||
main () {
|
||||
//Define the attributes to return
|
||||
String[] attributes = {"givenname", "surname", "o", "mail"};
|
||||
|
||||
//open the local address card source
|
||||
// (true = create if needed)
|
||||
AC_Source myLocalAddressBook = new LocalStore ("MyAddressBook.nab", true);
|
||||
AC newCard = new AC ();
|
||||
newCard.add (new AC_Attribute ("givenname", "Robert"));
|
||||
newCard.add (new AC_Attribute ("mail", "robert@ford.com"));
|
||||
newCard.add (new AC_Attribute ("o", "Ford Motor Company"));
|
||||
newCard.add (new AC_Attribute ("ou", "Audio"));
|
||||
newCard.add (new AC_Attribute ("c", "US"));
|
||||
|
||||
//try to store the new card
|
||||
try {
|
||||
myLocalAddressBook.addCard (newCard);
|
||||
}
|
||||
catch (AC_Exception ace) {
|
||||
//1) No write access to DB
|
||||
//2) All required attributes not provided
|
||||
//3) Network connection down
|
||||
//4) Card already in DB
|
||||
}
|
||||
|
||||
//try to change the card
|
||||
try {
|
||||
newCard.updateAttribute ("ou", "Electronics Division");
|
||||
myLocalAddressBook.updateCard (newCard);
|
||||
}
|
||||
catch (AC_Exception ace) {
|
||||
//1) No write access to DB or this card.
|
||||
//2) All required attributes not provided
|
||||
//3) Network connection down
|
||||
}
|
||||
|
||||
//try to delete an attribute from the card
|
||||
try {
|
||||
newCard.deleteAttribute ("ou");
|
||||
myLocalAddressBook.updateCard (newCard);
|
||||
}
|
||||
catch (AC_Exception ace) {
|
||||
//1) No write access to DB or this card
|
||||
//2) Network connection down
|
||||
//3) Card NOT in DB
|
||||
}
|
||||
|
||||
//try to delete the card
|
||||
try {
|
||||
myLocalAddressBook.deleteCard (newCard);
|
||||
}
|
||||
catch (AC_Exception ace) {
|
||||
//1) No write access to DB or this card
|
||||
//2) Network connection down
|
||||
//3) Card NOT in DB
|
||||
}
|
||||
|
||||
//AC_Sources close when they fall out of scope.
|
||||
}
|
||||
|
||||
|
||||
|
||||
//example #
|
||||
//List all cards and their attributes.
|
||||
public static void main(String argv[]) {
|
||||
//open the LDAP address card source
|
||||
IAC_Source Four11AddressBook = new LDAP_Server ("ldap.whowhere.com");
|
||||
|
||||
|
||||
|
||||
//define the card query.
|
||||
ITerm query = new TermEqual (new AC_Scope ("ObjectType", "Room"));
|
||||
|
||||
|
||||
AB.Search.Term query = new AC_Attribute ("objectclass", "resource");
|
||||
AB.Search.Term query = new AC_Attribute ("objectclass", "person");
|
||||
|
||||
|
||||
//All object of type room on the second floor.
|
||||
ITerm query = new AC_Scope ("Room", new TermEqual (new AC_Attribute ("Floor", "2")));
|
||||
|
||||
|
||||
|
||||
//Define the attributes to return
|
||||
String[] attributes = {"cn", "o", "mail"};
|
||||
String[] sortOrder = {"givenname", "surname"};
|
||||
|
||||
//query the LDAP server.
|
||||
AC_Set cardSet = Four11AddressBook.getCardSet (query, attributes);
|
||||
|
||||
//Sort the list.
|
||||
cardSet.sort (sortOrder);
|
||||
|
||||
//Enumerate thru the cards.
|
||||
for (Enumeration cardEnum = cardSet.getCardEnumeration(); cardEnum.hasMoreElements(); ) {
|
||||
AC card = (AC) cardEnum.nextElement();
|
||||
|
||||
System.out.println ("==== Card ====");
|
||||
AC_AttributeSet attrSet = card.getAttributeSet ();
|
||||
|
||||
//Enumerate thru the attributes.
|
||||
for (Enumeration attEnum = attrSet.elements(); attEnum.hasMoreElements(); ) {
|
||||
AC_Attribute attr = (AC_Attribute) attEnum.nextElement();
|
||||
|
||||
System.out.println ("Attr: Name = " + attr.getName() + " Value = " + attr.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
//AC_Sources close when they fall out of scope.
|
||||
// LDAP_Server.close ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static void main() {
|
||||
try {
|
||||
AC_Source Four11AddressBook = new LDAPServer ("lpad.four11.com", "lesters", "SecretPassword");
|
||||
|
||||
// search for all entries with surname of Jensen
|
||||
String MY_FILTER = "sn=lester";
|
||||
// String MY_SEARCHBASE = "o=Ace Industry, c=US";
|
||||
String MY_SEARCHBASE = "c=US";
|
||||
|
||||
LDAPSearchConstraints cons = ld.getSearchConstraints();
|
||||
cons.setBatchSize( 1 );
|
||||
AC_Set cardSet = ld.search( MY_SEARCHBASE,
|
||||
MY_FILTER,
|
||||
null,
|
||||
false,
|
||||
cons );
|
||||
|
||||
// Loop on results until finished
|
||||
while ( cardSet.hasMoreElements() ) {
|
||||
|
||||
// Next entry
|
||||
AC card = cardSet.nextElement();
|
||||
|
||||
// Get the attributes of the entry
|
||||
AC_AttributeSet attrs = card.getAttributeSet();
|
||||
Enumeration enumAttrs = attrs.getAttributes();
|
||||
|
||||
// Loop on attributes
|
||||
while ( enumAttrs.hasMoreElements() ) {
|
||||
AC_Attribute anAttr = (AC_Attribute) enumAttrs.nextElement();
|
||||
String attrName = anAttr.getName();
|
||||
System.out.println( "\t\t" + attrName );
|
||||
|
||||
// Loop on values for this attribute
|
||||
Enumeration enumVals = anAttr.getStringValues();
|
||||
while ( enumVals.hasMoreElements() ) {
|
||||
String aVal = ( String )enumVals.nextElement();
|
||||
System.out.println( "\t\t\t" + aVal );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( Exception e ) {
|
||||
System.out.prin
|
||||
*/
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public class TermAnd implements ITerm {
|
||||
ITerm fLeftTerm;
|
||||
ITerm fRightTerm;
|
||||
|
||||
public TermAnd (ITerm aLeftTerm, ITerm aRightTerm) {
|
||||
fLeftTerm = aLeftTerm;
|
||||
fRightTerm = aRightTerm;
|
||||
}
|
||||
|
||||
public String getExpression(IQueryString iqs) {
|
||||
return iqs.opAnd (fLeftTerm, fRightTerm);
|
||||
}
|
||||
|
||||
/** Call the Address Card Source to AND the left and right sets.
|
||||
*/
|
||||
public AC_IDSet getSet (IQuerySet iqs) {
|
||||
AC_IDSet leftCardIDs = fLeftTerm.getSet (iqs);
|
||||
AC_IDSet rightCardIDs = fRightTerm.getSet (iqs);
|
||||
|
||||
//create the merge cardID list for return.
|
||||
AC_IDSet mergedIDs = new AC_IDSet ();
|
||||
|
||||
//keep only card ID's that are in both left and right terms.
|
||||
for (int i = 0; i < leftCardIDs.size(); i++) {
|
||||
AC_ID id = (AC_ID) leftCardIDs.elementAt (i);
|
||||
if (rightCardIDs.contains (id))
|
||||
mergedIDs.addElement (id);
|
||||
}
|
||||
|
||||
return mergedIDs;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public class TermEqual implements ITerm {
|
||||
private IAttribute fAttribute;
|
||||
|
||||
public TermEqual (IAttribute anAttribute) {
|
||||
fAttribute = anAttribute;
|
||||
}
|
||||
|
||||
public String getExpression(IQueryString iqs) {
|
||||
return iqs.opEqual (fAttribute);
|
||||
}
|
||||
|
||||
/** Call the Address Card Source to find a set that's equal.
|
||||
*/
|
||||
public AC_IDSet getSet (IQuerySet iqs) {
|
||||
return iqs.opEqual (fAttribute);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public class TermNotEqual implements ITerm {
|
||||
private IAttribute fAttribute;
|
||||
|
||||
/**
|
||||
*/
|
||||
public TermNotEqual (IAttribute anAttribute) {
|
||||
fAttribute = anAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public String getExpression(IQueryString iqs) {
|
||||
return iqs.opNotEqual (fAttribute);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public AC_IDSet getSet (IQuerySet iqs) {
|
||||
return iqs.opNotEqual (fAttribute);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Lester Schueler <lesters@netscape.com>, 14 Nov 1997.
|
||||
*/
|
||||
|
||||
package grendel.addressbook.AddressCard;
|
||||
|
||||
//************************
|
||||
//************************
|
||||
public class TermOr implements ITerm {
|
||||
ITerm fLeftTerm;
|
||||
ITerm fRightTerm;
|
||||
|
||||
public TermOr (ITerm aLeftTerm, ITerm aRightTerm) {
|
||||
fLeftTerm = aLeftTerm;
|
||||
fRightTerm = aRightTerm;
|
||||
}
|
||||
|
||||
public String getExpression(IQueryString iqs) {
|
||||
return iqs.opOr (fLeftTerm, fRightTerm);
|
||||
}
|
||||
|
||||
/** Logically or the left and right sets.
|
||||
*/
|
||||
public AC_IDSet getSet (IQuerySet iqs) {
|
||||
AC_IDSet leftCardIDs = fLeftTerm.getSet (iqs);
|
||||
AC_IDSet rightCardIDs = fRightTerm.getSet (iqs);
|
||||
|
||||
//merge and sort the left and right lists.
|
||||
AC_IDSet mergedIDs = new AC_IDSet (leftCardIDs);
|
||||
mergedIDs.addSet (rightCardIDs);
|
||||
mergedIDs.sort(AC_IDSet.ASCENDING);
|
||||
|
||||
//Don't process any more if the merged set is emtpy.
|
||||
if (0 == mergedIDs.size())
|
||||
return mergedIDs; //return an empty merged set.
|
||||
|
||||
//prime the pump.
|
||||
String lastID = (String) mergedIDs.elementAt(0);
|
||||
|
||||
//remove any duplicates from the SORTED list.
|
||||
for (int i = 0; i < mergedIDs.size(); ) {
|
||||
String currentID = (String) mergedIDs.elementAt(i);
|
||||
|
||||
//if the last equals this (this list is sorted) then remove this duplicate.
|
||||
if (lastID.equals (currentID)) {
|
||||
mergedIDs.removeElementAt (i);
|
||||
}
|
||||
else {
|
||||
lastID = currentID;
|
||||
i++; //advance to the next cardID
|
||||
}
|
||||
}
|
||||
|
||||
return mergedIDs;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License
|
||||
# Version 1.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.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
# the License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Grendel mail/news client.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
SUBDIRS= \
|
||||
util \
|
||||
$(NULL)
|
||||
|
||||
include ../rules.mk
|
|
@ -0,0 +1,7 @@
|
|||
This is Grendel -- a Java mail/news client.
|
||||
|
||||
Originally the calypso package was a general utility package for all of
|
||||
the Xena project; what is present here are just the parts of Calypso
|
||||
that are used by Grendel.
|
||||
|
||||
See http://www.mozilla.org/projects/grendel/ for more info.
|
|
@ -0,0 +1,289 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
/** A class for counting in a variety of bases.
|
||||
*/
|
||||
|
||||
public class Abacus
|
||||
{
|
||||
|
||||
/************************************************
|
||||
* Formatting Strings
|
||||
************************************************/
|
||||
|
||||
public final static String ones[]=
|
||||
{"zero","one ","two ","three ","four ","five ",
|
||||
"six ","seven ","eight ","nine ","ten "};
|
||||
|
||||
public final static String teens[]=
|
||||
{"ten ","eleven ","twelve ","thirteen ","fourteen ","fifteen ",
|
||||
"sixteen ","seventeen ","eighteen ","nineteen "};
|
||||
|
||||
public final static String tens[]=
|
||||
{"","ten ","twenty ","thirty ","forty ","fifty ",
|
||||
"sixty ","seventy ","eighty ","ninety ","hundred "};
|
||||
|
||||
public final static String bases[] =
|
||||
{"","hundred ","thousand ","million ","billion ","trillion ","quadrillion "};
|
||||
|
||||
protected final static String gAlphaChars = "abcdefghijklmnopqrstuvwxyz";
|
||||
protected final static String gRomanCharsA = "ixcm";
|
||||
protected final static String gRomanCharsB = "vld?";
|
||||
protected final static String gHexChars = "0123456789abcdef";
|
||||
protected final static String gBinaryChars = "01";
|
||||
|
||||
/************************************************
|
||||
* Data members...
|
||||
************************************************/
|
||||
|
||||
//notice that we don't have any?
|
||||
|
||||
/** Formats the value as an alpha string
|
||||
*
|
||||
*
|
||||
* @return
|
||||
* @author gess 05-05-97 12:22pm
|
||||
* @notes
|
||||
*/
|
||||
public static String getAlphaString(int aValue)
|
||||
{
|
||||
return getSeriesString(Math.abs(aValue)-1,gAlphaChars,-1,gAlphaChars.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given integer value into a roman numeral string
|
||||
*
|
||||
* @param aValue - int to be converted to roman
|
||||
* @return new string
|
||||
* @author gess 05-05-97 12:53pm
|
||||
* @notes Those pesky romans used dashed above a value to multiply
|
||||
* that number by 1000. This has the unfortunate side effect
|
||||
* that without special font treatment, we cant represent
|
||||
* numbers in roman above 3999.
|
||||
* THIS METHOD HANDLES VALUES IN THE RANGE [1..3999].
|
||||
* (any other value is converted to simple numeric format.)
|
||||
*/
|
||||
public static String getRomanString(int aValue)
|
||||
{
|
||||
StringBuffer addOn = new StringBuffer();
|
||||
StringBuffer result = new StringBuffer();
|
||||
StringBuffer decStr = new StringBuffer();
|
||||
|
||||
decStr.append(aValue);
|
||||
|
||||
int len=decStr.length();
|
||||
int romanPos=len;
|
||||
int n,digitPos;
|
||||
boolean negative=(aValue<0);
|
||||
|
||||
aValue=Math.abs(aValue);
|
||||
for(digitPos=0;digitPos<len;digitPos++)
|
||||
{
|
||||
romanPos--;
|
||||
addOn.setLength(0);
|
||||
switch(decStr.charAt(digitPos))
|
||||
{
|
||||
case '3': addOn.append(gRomanCharsA.charAt(romanPos));
|
||||
case '2': addOn.append(gRomanCharsA.charAt(romanPos));
|
||||
case '1': addOn.append(gRomanCharsA.charAt(romanPos));
|
||||
break;
|
||||
|
||||
case '4':
|
||||
addOn.append(gRomanCharsA.charAt(romanPos));
|
||||
|
||||
case '5': case '6':
|
||||
case '7': case '8':
|
||||
addOn.append(gRomanCharsB.charAt(romanPos));
|
||||
for(n=0;n<(decStr.charAt(digitPos)-'5');n++)
|
||||
addOn.append(gRomanCharsA.charAt(romanPos));
|
||||
break;
|
||||
case '9':
|
||||
addOn.append(gRomanCharsA.charAt(romanPos));
|
||||
addOn.append(gRomanCharsA.charAt(romanPos+1));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
result.append(addOn);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given integer value into a hexstring
|
||||
*
|
||||
* @param aValue - int to be converted to hex string
|
||||
* @return new string
|
||||
* @author gess 05-05-97 12:53pm
|
||||
*
|
||||
*/
|
||||
public static String getHexString(int aValue)
|
||||
{
|
||||
if (aValue<0)
|
||||
aValue=65536-Math.abs(aValue);
|
||||
return getSeriesString(aValue,gHexChars,0,gHexChars.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given integer value into a string of binary digits
|
||||
*
|
||||
* @param aValue - int to be converted to binary string
|
||||
* @return new string
|
||||
* @author gess 05-05-97 12:53pm
|
||||
*
|
||||
*/
|
||||
public static String getBinaryString(int aValue)
|
||||
{
|
||||
if (aValue<0)
|
||||
aValue=65536-Math.abs(aValue);
|
||||
return getSeriesString(aValue,gBinaryChars,0,gBinaryChars.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given integer value into spoken string (one, two, three...)
|
||||
*
|
||||
* @param aValue - int to be converted to hex string
|
||||
* @return new stringbuffer
|
||||
* @author gess 05-05-97 12:53pm
|
||||
*
|
||||
*/
|
||||
public static String getSpokenString(int aValue)
|
||||
{
|
||||
int root=1000000000;
|
||||
int expn=4;
|
||||
int modu=0;
|
||||
int div=0;
|
||||
int temp=0;
|
||||
StringBuffer result= new StringBuffer();
|
||||
|
||||
if (aValue<0)
|
||||
result.append('-');
|
||||
|
||||
aValue=Math.abs(aValue);
|
||||
while((0!=root) && (0!=aValue))
|
||||
{
|
||||
temp=aValue/root;
|
||||
if(0!=temp)
|
||||
{
|
||||
div=temp/100;
|
||||
if (0!=div) //start with hundreds part
|
||||
{
|
||||
result.append(ones[div]);
|
||||
result.append(bases[1]);
|
||||
}
|
||||
modu=(temp%10);
|
||||
div=((temp%100)/10);
|
||||
|
||||
if (0!=div)
|
||||
if (div<2)
|
||||
{
|
||||
result.append(teens[modu]);
|
||||
modu=0;
|
||||
}
|
||||
else result.append(tens[div]);
|
||||
if (0!=modu)
|
||||
result.append(ones[modu]); // do remainder.
|
||||
aValue-=(temp*root);
|
||||
if (expn>1) result.append(bases[expn]);
|
||||
}
|
||||
expn--;
|
||||
root/=1000;
|
||||
}
|
||||
if (0==result.length())
|
||||
result.append("zero");
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given integer value into a series string. These are any
|
||||
* arbitrary but repeating pattern of characters.
|
||||
*
|
||||
* @param aValue - int to be converted to series string
|
||||
* @return new string
|
||||
* @author gess 05-05-97 12:53pm
|
||||
* @notes this method gets used for binary and hex conversion
|
||||
*/
|
||||
public static String getSeriesString(int aValue,String aCharSet,int anOffset,int aBase)
|
||||
{
|
||||
int ndex=0;
|
||||
int root=1;
|
||||
int next=aBase;
|
||||
int expn=1;
|
||||
StringBuffer result=new StringBuffer();
|
||||
|
||||
aValue=Math.abs(aValue); // must be positive here...
|
||||
while(next<=aValue) // scale up in baseN; exceed current value.
|
||||
{
|
||||
root=next;
|
||||
next*=aBase;
|
||||
expn++;
|
||||
}
|
||||
|
||||
while(0!=(expn--))
|
||||
{
|
||||
ndex = ((root<=aValue) && (0!=root)) ? (aValue/root): 0;
|
||||
aValue%=root;
|
||||
if(root>1)
|
||||
result.append(aCharSet.charAt(ndex+(1*anOffset)));
|
||||
else result.append(aCharSet.charAt(ndex));
|
||||
root/=aBase;
|
||||
};
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static void PadPrint(int aValue,int width)
|
||||
{
|
||||
StringBuffer temp=new StringBuffer();
|
||||
temp.append(aValue);
|
||||
PadPrint(temp.toString(),width);
|
||||
}
|
||||
|
||||
public static void PadPrint(String aString, int aWidth)
|
||||
{
|
||||
System.out.print(aString);
|
||||
int padCount=aWidth-aString.length();
|
||||
if(padCount>0)
|
||||
for(int i=0;i<padCount;i++)
|
||||
System.out.print(" ");
|
||||
}
|
||||
|
||||
|
||||
public static void main(String argv[])
|
||||
{
|
||||
int index=0;
|
||||
|
||||
System.out.println(" ");
|
||||
System.out.println("Value Hex Roman Series Binary Spoken ");
|
||||
System.out.println("-----------------------------------------------------------------------------");
|
||||
for(index=1002;index<1205;index++)
|
||||
{
|
||||
PadPrint(index,8);
|
||||
PadPrint(Abacus.getHexString(index),10);
|
||||
PadPrint(Abacus.getRomanString(index),10);
|
||||
PadPrint(Abacus.getSeriesString(index,"ABCD",0,4),10);
|
||||
PadPrint(Abacus.getBinaryString(index),16);
|
||||
PadPrint(Abacus.getSpokenString(index),10);
|
||||
System.out.println("");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This creates an enumerator that can run through an array.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class ArrayEnumeration implements Enumeration {
|
||||
int i = 0;
|
||||
Object a[];
|
||||
public ArrayEnumeration(Object a[]) { this.a = a; }
|
||||
public Object nextElement() {
|
||||
if (i < a.length) return a[i++];
|
||||
else throw new NoSuchElementException();
|
||||
}
|
||||
public boolean hasMoreElements() { return (a != null && i < a.length); }
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
/**
|
||||
* Simple assertion class that throws exceptions when an assertion
|
||||
* fails.
|
||||
*/
|
||||
public final class Assert {
|
||||
// Enabled flag. In theory if this is set to false the assertion
|
||||
// code can get compiled out when optimizing.
|
||||
static final boolean kEnabled = true;
|
||||
|
||||
/**
|
||||
* Throw an exception if aCondition is false.
|
||||
*/
|
||||
final public static void Assertion(boolean aCondition) {
|
||||
if (kEnabled) {
|
||||
if (!aCondition) {
|
||||
throw new AssertionError("assertion");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception if aCondition is false.
|
||||
*/
|
||||
final public static void Assertion(boolean aCondition, String aMessage) {
|
||||
if (kEnabled) {
|
||||
if (!aCondition) {
|
||||
throw new AssertionError("assertion: " + aMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception always. Used when the caller runs across some
|
||||
* code that should never be reached.
|
||||
*/
|
||||
final public static void NotReached(String msg) {
|
||||
if (kEnabled) {
|
||||
throw new AssertionError("not reached: " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception always. Used when the caller runs across some
|
||||
* unimplemented functionality in pre-release code.
|
||||
*/
|
||||
final public static void NotYetImplemented(String msg) {
|
||||
if (kEnabled) {
|
||||
throw new AssertionError("not yet implemented: " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception if aCondition is false.
|
||||
*/
|
||||
final public static void PreCondition(boolean aCondition) {
|
||||
if (kEnabled) {
|
||||
if (!aCondition) {
|
||||
throw new AssertionError("precondition");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception if aCondition is false.
|
||||
*/
|
||||
final public static void PreCondition(boolean aCondition, String aMessage) {
|
||||
if (kEnabled) {
|
||||
if (!aCondition) {
|
||||
throw new AssertionError("precondition: " + aMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception if aCondition is false.
|
||||
*/
|
||||
final public static void PostCondition(boolean aCondition) {
|
||||
if (kEnabled) {
|
||||
if (!aCondition) {
|
||||
throw new AssertionError("precondition");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception if aCondition is false.
|
||||
*/
|
||||
final public static void PostCondition(boolean aCondition, String aMessage) {
|
||||
if (kEnabled) {
|
||||
if (!aCondition) {
|
||||
throw new AssertionError("precondition: " + aMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
/**
|
||||
* Assertion errors are thrown when assertion code is invoked
|
||||
* and fails to operate properly.
|
||||
*/
|
||||
public class AssertionError extends Error {
|
||||
public AssertionError() {
|
||||
}
|
||||
|
||||
public AssertionError(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
/**
|
||||
* Assertion exceptions are thrown when assertion code is invoked
|
||||
* and fails to operate properly.
|
||||
*/
|
||||
public class AssertionException extends Error {
|
||||
public AssertionException() {
|
||||
}
|
||||
|
||||
public AssertionException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,222 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
/**
|
||||
* Atom's are unique objects that you can use the object address
|
||||
* to perform equality tests. This class accepts variants on
|
||||
* String's to create the Atom's from.
|
||||
*/
|
||||
public final class Atom {
|
||||
String fString;
|
||||
int fHashCode;
|
||||
|
||||
private static final AtomTable gAtoms = new AtomTable();
|
||||
|
||||
/**
|
||||
* Private constructor used by static allocators.
|
||||
*/
|
||||
private Atom(String aString, int aHashCode) {
|
||||
fString = aString;
|
||||
fHashCode = aHashCode;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return fString;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return fHashCode;
|
||||
}
|
||||
|
||||
public boolean equals(Object aObject) {
|
||||
return aObject == this;
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
synchronized (gAtoms) {
|
||||
gAtoms.remove(fString, fHashCode);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX deprecated entry point. Use Find instead
|
||||
static private int gNoisyUsageCount = 10;
|
||||
static public Atom ForObject(Object aObject) {
|
||||
synchronized (gAtoms) {
|
||||
if (gNoisyUsageCount > 0) {
|
||||
try {
|
||||
throw new RuntimeException("Atom.ForObject: deprecated method called! Use Atom.Find instead. Object:" + aObject.toString());
|
||||
}
|
||||
catch(RuntimeException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
gNoisyUsageCount--;
|
||||
}
|
||||
return gAtoms.find(aObject.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the atom for the given argument string. If the atom doesn't
|
||||
* already exist then it is created.
|
||||
*/
|
||||
static public Atom Find(String aString) {
|
||||
synchronized (gAtoms) {
|
||||
return gAtoms.find(aString);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the atom for the given argument string. If the atom doesn't
|
||||
* already exist then it is created.
|
||||
*/
|
||||
static public Atom Find(StringBuf aString) {
|
||||
synchronized (gAtoms) {
|
||||
return gAtoms.find(aString);
|
||||
}
|
||||
}
|
||||
|
||||
private static int gNextAtomID;
|
||||
static public Atom UniqueAtom(String aPrefix) {
|
||||
synchronized (gAtoms) {
|
||||
StringBuf sbuf = StringBuf.Alloc();
|
||||
Atom atom = null;
|
||||
for (;;) {
|
||||
int id = ++gNextAtomID;
|
||||
sbuf.setLength(0);
|
||||
sbuf.append(aPrefix);
|
||||
sbuf.append(id);
|
||||
if (!gAtoms.contains(sbuf)) {
|
||||
atom = gAtoms.find(sbuf);
|
||||
break;
|
||||
}
|
||||
// Hmmm. Somebody else recorded an atom with this name. Try
|
||||
// again with the next id
|
||||
}
|
||||
StringBuf.Recycle(sbuf);
|
||||
return atom;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
// key's are String's/StringBuf's
|
||||
// value's are WeakLink's which hold a weak reference to Atom's
|
||||
|
||||
static final class AtomTable extends HashtableBase {
|
||||
Atom find(String aKey) {
|
||||
return find(aKey, HashCodeFor(aKey));
|
||||
}
|
||||
|
||||
Atom find(StringBuf aKey) {
|
||||
return find(aKey, HashCodeFor(aKey));
|
||||
}
|
||||
|
||||
private Atom find(Object aKey, int aHash) {
|
||||
if (hashCodes == null) {
|
||||
// create tables
|
||||
grow();
|
||||
}
|
||||
int index = tableIndexFor(aKey, aHash);
|
||||
Atom atom = null;
|
||||
WeakLink link = (WeakLink) elements[index];
|
||||
if (link == null) {
|
||||
if (hashCodes[index] == EMPTY) {
|
||||
// If the total number of occupied slots (either with a real
|
||||
// element or a removed marker) gets too big, grow the table.
|
||||
if (totalCount >= capacity) {
|
||||
grow();
|
||||
return find(aKey, aHash);
|
||||
}
|
||||
totalCount++;
|
||||
}
|
||||
count++;
|
||||
|
||||
hashCodes[index] = aHash;
|
||||
keys[index] = aKey.toString();
|
||||
elements[index] = link = new WeakLink();
|
||||
} else {
|
||||
atom = (Atom) link.get();
|
||||
}
|
||||
|
||||
// Create atom if necessary
|
||||
if (atom == null) {
|
||||
atom = new Atom(aKey.toString(), aHash);
|
||||
link.setThing(atom);
|
||||
}
|
||||
return atom;
|
||||
}
|
||||
|
||||
// XXX replace with a faster better function
|
||||
static final int HashCodeFor(String aString) {
|
||||
int h = 0;
|
||||
int len = aString.length();
|
||||
if (len < 16) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
h = (h * 37) + aString.charAt(i);
|
||||
}
|
||||
} else {
|
||||
// only sample some characters
|
||||
int skip = len / 8;
|
||||
for (int i = len, off = 0 ; i > 0; i -= skip, off += skip) {
|
||||
h = (h * 39) + aString.charAt(off);
|
||||
}
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
static final int HashCodeFor(StringBuf aString) {
|
||||
int h = 0;
|
||||
int len = aString.length();
|
||||
if (len < 16) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
h = (h * 37) + aString.charAt(i);
|
||||
}
|
||||
} else {
|
||||
// only sample some characters
|
||||
int skip = len / 8;
|
||||
for (int i = len, off = 0 ; i > 0; i -= skip, off += skip) {
|
||||
h = (h * 39) + aString.charAt(off);
|
||||
}
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
boolean contains(StringBuf aKey) {
|
||||
if (hashCodes == null) {
|
||||
return false;
|
||||
}
|
||||
int index = tableIndexFor(aKey, HashCodeFor(aKey));
|
||||
WeakLink link = (WeakLink) elements[index];
|
||||
if (link != null) {
|
||||
return link.get() != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void remove(String aKey, int aHashCode) {
|
||||
int index = tableIndexFor(aKey, aHashCode);
|
||||
count--;
|
||||
hashCodes[index] = REMOVED;
|
||||
keys[index] = null;
|
||||
elements[index] = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Special hashtable that uses Atoms as keys. This extends HashtableBase to
|
||||
* expose a public Atom based api
|
||||
* This hastable uses identity comparisons on keys
|
||||
*
|
||||
* @author psl 10-15-97 1:22pm
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*/
|
||||
public class AtomHashtable extends HashtableBase
|
||||
{
|
||||
/** Constructs an empty Hashtable. The Hashtable will grow on demand
|
||||
* as more elements are added.
|
||||
*/
|
||||
public AtomHashtable ()
|
||||
{
|
||||
super ();
|
||||
}
|
||||
|
||||
/** Constructs a Hashtable capable of holding at least
|
||||
* <b>initialCapacity</b> elements before needing to grow.
|
||||
*/
|
||||
public AtomHashtable (int aInitialCapacity)
|
||||
{
|
||||
super (aInitialCapacity);
|
||||
}
|
||||
|
||||
/** Returns an Object array containing the Hashtable's keys.
|
||||
*/
|
||||
public Atom[] keysArray ()
|
||||
{
|
||||
Atom[] result = new Atom[count];
|
||||
getKeysArray (result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Returns an Object array containing the Hashtable's elements.
|
||||
*/
|
||||
public Object[] elementsArray ()
|
||||
{
|
||||
Object[] result = new Object[count];
|
||||
getElementsArray (result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Returns <b>true</b> if the Hashtable contains the element. This method
|
||||
* is slow -- O(n) -- because it must scan the table searching for the
|
||||
* element.
|
||||
*/
|
||||
public boolean contains (Object aElement)
|
||||
{
|
||||
return containsElement (aElement);
|
||||
}
|
||||
|
||||
/** Returns <b>true</b> if the Hashtable contains the key <b>key</b>.
|
||||
*/
|
||||
public boolean containsKey (Atom aKey)
|
||||
{
|
||||
return (get (aKey) != null);
|
||||
}
|
||||
|
||||
/** Returns the element associated with the <b>key</b>. This method returns
|
||||
* <b>null</b> if the Hashtable does not contain <b>key</b>. Hashtable
|
||||
* hashes and compares <b>key</b> using <b>hashCode()</b> and
|
||||
* <b>equals()</b>.
|
||||
*/
|
||||
public Object get (Atom aKey)
|
||||
{
|
||||
// We need to short-circuit here since the data arrays may not have
|
||||
// been allocated yet.
|
||||
|
||||
if (count == 0)
|
||||
return null;
|
||||
|
||||
return elements[tableIndexFor (aKey, hash (aKey))];
|
||||
}
|
||||
|
||||
/** Removes <b>key</b> and the element associated with it from the
|
||||
* Hashtable. Returns the element associated with <b>key</b>, or
|
||||
* <b>null</b> if <b>key</b> was not present.
|
||||
*/
|
||||
public Object remove (Atom aKey)
|
||||
{
|
||||
return removeKey (aKey);
|
||||
}
|
||||
|
||||
/** Places the <b>key</b>/<b>element</b> pair in the Hashtable. Neither
|
||||
* <b>key</b> nor <b>element</b> may be <b>null</b>. Returns the old
|
||||
* element associated with <b>key</b>, or <b>null</b> if the <b>key</b>
|
||||
* was not present.
|
||||
*/
|
||||
public Object put (Atom aKey, Object aElement)
|
||||
{
|
||||
return super.put (aKey, aElement);
|
||||
}
|
||||
|
||||
int hash (Object aKey)
|
||||
{
|
||||
return ((Atom)aKey).fHashCode;
|
||||
}
|
||||
|
||||
int hash (Atom aKey)
|
||||
{
|
||||
return aKey.fHashCode;
|
||||
}
|
||||
|
||||
/** Primitive method used internally to find slots in the
|
||||
* table. If the key is present in the table, this method will return the
|
||||
* index
|
||||
* under which it is stored. If the key is not present, then this
|
||||
* method will return the index under which it can be put. The caller
|
||||
* must look at the hashCode at that index to differentiate between
|
||||
* the two possibilities.
|
||||
*/
|
||||
int tableIndexFor (Object aKey, int aHash)
|
||||
{
|
||||
int product, testHash, index, step, removedIndex, probeCount;
|
||||
|
||||
product = aHash * A;
|
||||
index = product >>> shift;
|
||||
|
||||
// Probe the first slot in the table. We keep track of the first
|
||||
// index where we found a REMOVED marker so we can return that index
|
||||
// as the first available slot if the key is not already in the table.
|
||||
|
||||
testHash = hashCodes[index];
|
||||
|
||||
if (testHash == aHash) {
|
||||
if (aKey == keys[index])
|
||||
return index;
|
||||
removedIndex = -1;
|
||||
} else if (testHash == EMPTY)
|
||||
return index;
|
||||
else if (testHash == REMOVED)
|
||||
removedIndex = index;
|
||||
else
|
||||
removedIndex = -1;
|
||||
|
||||
// Our first probe has failed, so now we need to start looking
|
||||
// elsewhere in the table.
|
||||
|
||||
step = ((product >>> (2 * shift - 32)) & indexMask) | 1;
|
||||
probeCount = 1;
|
||||
|
||||
do
|
||||
{
|
||||
probeCount++;
|
||||
index = (index + step) & indexMask;
|
||||
|
||||
testHash = hashCodes[index];
|
||||
|
||||
if (testHash == aHash) {
|
||||
if (aKey == keys[index])
|
||||
return index;
|
||||
} else if (testHash == EMPTY) {
|
||||
if (removedIndex < 0)
|
||||
return index;
|
||||
else
|
||||
return removedIndex;
|
||||
} else if (testHash == REMOVED && removedIndex == -1)
|
||||
removedIndex = index;
|
||||
|
||||
} while (probeCount <= totalCount);
|
||||
|
||||
// Something very bad has happened.
|
||||
|
||||
throw new Error("Hashtable overflow");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
/**
|
||||
* Simple attribute/value pair class
|
||||
*
|
||||
* XXX add in a recylcer
|
||||
* XXX add in a method to reconsitute one from an InputStream/String?
|
||||
*/
|
||||
public class AttributeValuePair {
|
||||
protected Atom fName;
|
||||
protected String fValue;
|
||||
|
||||
public AttributeValuePair(String aName, String aValue) {
|
||||
this(Atom.Find(aName), aValue);
|
||||
}
|
||||
|
||||
public AttributeValuePair(Atom aName, String aValue) {
|
||||
fName = aName;
|
||||
fValue = aValue;
|
||||
}
|
||||
|
||||
public Atom getName() {
|
||||
return fName;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return fValue;
|
||||
}
|
||||
|
||||
public boolean equals(Object aObject) {
|
||||
if ((null != aObject) && (aObject instanceof AttributeValuePair)) {
|
||||
AttributeValuePair other = (AttributeValuePair) aObject;
|
||||
if (fName.equals(other.fName)) {
|
||||
if (fValue != null) {
|
||||
return fValue.equals(other.fValue);
|
||||
}
|
||||
if (other.fValue == null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int h = fName.hashCode();
|
||||
if (null != fValue) {
|
||||
h = (h << 5) + fValue.hashCode();
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuf sbuf = StringBuf.Alloc();
|
||||
sbuf.append(fName);
|
||||
if (fValue != null) {
|
||||
sbuf.append("=");
|
||||
sbuf.append(quoteValue());
|
||||
}
|
||||
String rv = sbuf.toString();
|
||||
StringBuf.Recycle(sbuf);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quote the value portion of an attribute,value pair making it
|
||||
* suitable for reading in later. We assume "C" style quoting
|
||||
* by backslashing quotes embedded in the value.
|
||||
*/
|
||||
protected String quoteValue() {
|
||||
if (fValue == null) {
|
||||
return "\"\"";
|
||||
}
|
||||
StringBuf buf = StringBuf.Alloc();
|
||||
buf.append('"');
|
||||
int n = fValue.length();
|
||||
for (int i = 0; i < n; i++) {
|
||||
char ch = fValue.charAt(i);
|
||||
if (ch == '"') {
|
||||
buf.append("\"");
|
||||
} else {
|
||||
buf.append(ch);
|
||||
}
|
||||
}
|
||||
buf.append('"');
|
||||
String rv = buf.toString();
|
||||
StringBuf.Recycle(buf);
|
||||
return rv;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,918 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
/**
|
||||
* This class is similar to java/lang/StringBuffer with the following changes:
|
||||
* <UL><LI>Stores bytes, not chars
|
||||
* <LI>None of the methods are synchronized
|
||||
* <LI>There is no sharing of the character array
|
||||
* <LI>Converting to a String requires a copy of the character data
|
||||
* <LI>Alloc and Recycle are provided to speed up allocation
|
||||
* <LI>A bunch of useful operations are provided (comparisons, etc.)
|
||||
* </UL>
|
||||
*/
|
||||
public final class ByteBuf {
|
||||
private byte value[];
|
||||
private int count;
|
||||
|
||||
// static ByteBufRecycler gRecycler;
|
||||
|
||||
/**
|
||||
* Constructs an empty String buffer, reusing one from the
|
||||
* recycler.
|
||||
*/
|
||||
static synchronized public ByteBuf Alloc() {
|
||||
return new ByteBuf();
|
||||
// if (gRecycler == null) {
|
||||
// gRecycler = new ByteBufRecycler();
|
||||
// }
|
||||
// return gRecycler.alloc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Release a ByteBuf to the recycler. It is up to the caller
|
||||
* to ensure that buffer is no longer being used otherwise
|
||||
* unpredicatable program behavior will result.
|
||||
*/
|
||||
static synchronized public void Recycle(ByteBuf aBuf) {
|
||||
// if (gRecycler == null) {
|
||||
// gRecycler = new ByteBufRecycler();
|
||||
// }
|
||||
// gRecycler.recycle(aBuf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty the recycler discarding any cached ByteBuf objects
|
||||
*/
|
||||
static synchronized public void EmptyRecycler() {
|
||||
// if (null != gRecycler) {
|
||||
// gRecycler = null;
|
||||
// }
|
||||
}
|
||||
|
||||
static void classFinalize() throws Throwable {
|
||||
// Poof! Now we are unloadable even though we have a static
|
||||
// variable.
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty String buffer.
|
||||
*/
|
||||
public ByteBuf() {
|
||||
this(16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty byte buffer with the specified initial length.
|
||||
* @param length the initial length
|
||||
*/
|
||||
public ByteBuf(int length) {
|
||||
value = new byte[length];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a byte buffer with the specified initial value.
|
||||
* @param str the initial value of the buffer
|
||||
*/
|
||||
public ByteBuf(String str) {
|
||||
this(str.length() + 16);
|
||||
append(str);
|
||||
}
|
||||
|
||||
public ByteBuf(byte bytes[], int offset, int length) {
|
||||
value = new byte[length];
|
||||
System.arraycopy(bytes, offset, value, 0, length);
|
||||
count = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length (character count) of the buffer.
|
||||
*/
|
||||
public int length() {
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current capacity of the String buffer. The capacity
|
||||
* is the amount of storage available for newly inserted
|
||||
* characters; beyond which an allocation will occur.
|
||||
*/
|
||||
public int capacity() {
|
||||
return value.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the capacity of the buffer is at least equal to the
|
||||
* specified minimum.
|
||||
* @param minimumCapacity the minimum desired capacity
|
||||
*/
|
||||
public void ensureCapacity(int minimumCapacity) {
|
||||
int maxCapacity = value.length;
|
||||
|
||||
if (minimumCapacity > maxCapacity) {
|
||||
int newCapacity = (maxCapacity + 1) * 2;
|
||||
if (minimumCapacity > newCapacity) {
|
||||
newCapacity = minimumCapacity;
|
||||
}
|
||||
|
||||
byte newValue[] = new byte[newCapacity];
|
||||
System.arraycopy(value, 0, newValue, 0, count);
|
||||
value = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the length of the String. If the length is reduced, characters
|
||||
* are lost. If the length is extended, the values of the new characters
|
||||
* are set to 0.
|
||||
* @param newLength the new length of the buffer
|
||||
* @exception StringIndexOutOfBoundsException If the length is invalid.
|
||||
*/
|
||||
public void setLength(int newLength) {
|
||||
if (newLength < 0) {
|
||||
throw new StringIndexOutOfBoundsException(newLength);
|
||||
}
|
||||
if (count < newLength) {
|
||||
ensureCapacity(newLength);
|
||||
for (; count < newLength; count++) {
|
||||
value[count] = '\0';
|
||||
}
|
||||
}
|
||||
count = newLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the byte at the specified index. An index ranges
|
||||
* from 0..length()-1.
|
||||
* @param index the index of the desired character
|
||||
* @exception StringIndexOutOfBoundsException If the index is invalid.
|
||||
*/
|
||||
public byte byteAt(int index) {
|
||||
if ((index < 0) || (index >= count)) {
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
}
|
||||
return value[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the characters of the specified substring (determined by
|
||||
* srcBegin and srcEnd) into the character array, starting at the
|
||||
* array's dstBegin location. Both srcBegin and srcEnd must be legal
|
||||
* indexes into the buffer.
|
||||
* @param srcBegin begin copy at this offset in the String
|
||||
* @param srcEnd stop copying at this offset in the String
|
||||
* @param dst the array to copy the data into
|
||||
* @param dstBegin offset into dst
|
||||
* @exception StringIndexOutOfBoundsException If there is an invalid index into the buffer.
|
||||
*/
|
||||
public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) {
|
||||
if ((srcBegin < 0) || (srcBegin >= count)) {
|
||||
throw new StringIndexOutOfBoundsException(srcBegin);
|
||||
}
|
||||
if ((srcEnd < 0) || (srcEnd > count)) {
|
||||
throw new StringIndexOutOfBoundsException(srcEnd);
|
||||
}
|
||||
if (srcBegin < srcEnd) {
|
||||
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the byte at the specified index to be ch.
|
||||
* @param index the index of the character
|
||||
* @param ch the new character
|
||||
* @exception StringIndexOutOfBoundsException If the index is invalid.
|
||||
*/
|
||||
public void setByteAt(int index, byte b) {
|
||||
if ((index < 0) || (index >= count)) {
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
}
|
||||
value[index] = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an object to the end of this buffer.
|
||||
* @param obj the object to be appended
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
*/
|
||||
public ByteBuf append(Object obj) {
|
||||
return append(String.valueOf(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a String to the end of this buffer. This just appends one byte
|
||||
* per char; it strips off the upper 8 bits. If you want the localized
|
||||
* method of converting chars to bytes, use append(String.getBytes()).
|
||||
* @param str the String to be appended
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
*/
|
||||
public ByteBuf append(String str) {
|
||||
if (str == null) {
|
||||
str = String.valueOf(str);
|
||||
}
|
||||
|
||||
int len = str.length();
|
||||
ensureCapacity(count + len);
|
||||
for (int i=0 ; i<len ; i++) {
|
||||
value[count++] = (byte) str.charAt(i);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an array of bytes to the end of this buffer.
|
||||
* @param str the characters to be appended
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
*/
|
||||
public ByteBuf append(byte str[]) {
|
||||
int len = str.length;
|
||||
ensureCapacity(count + len);
|
||||
System.arraycopy(str, 0, value, count, len);
|
||||
count += len;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a part of an array of characters to the end of this buffer.
|
||||
* @param str the characters to be appended
|
||||
* @param offset where to start
|
||||
* @param len the number of characters to add
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
*/
|
||||
public ByteBuf append(byte str[], int offset, int len) {
|
||||
ensureCapacity(count + len);
|
||||
System.arraycopy(str, offset, value, count, len);
|
||||
count += len;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ByteBuf append(ByteBuf buf) {
|
||||
append(buf.toBytes(), 0, buf.length());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a boolean to the end of this buffer.
|
||||
* @param b the boolean to be appended
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
*/
|
||||
public ByteBuf append(boolean b) {
|
||||
return append(String.valueOf(b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a byte to the end of this buffer.
|
||||
* @param ch the character to be appended
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
*/
|
||||
public ByteBuf append(byte b) {
|
||||
ensureCapacity(count + 1);
|
||||
value[count++] = b;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an integer to the end of this buffer.
|
||||
* @param i the integer to be appended
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
*/
|
||||
public ByteBuf append(int i) {
|
||||
return append(String.valueOf(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a long to the end of this buffer.
|
||||
* @param l the long to be appended
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
*/
|
||||
public ByteBuf append(long l) {
|
||||
return append(String.valueOf(l));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a float to the end of this buffer.
|
||||
* @param f the float to be appended
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
*/
|
||||
public ByteBuf append(float f) {
|
||||
return append(String.valueOf(f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a double to the end of this buffer.
|
||||
* @param d the double to be appended
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
*/
|
||||
public ByteBuf append(double d) {
|
||||
return append(String.valueOf(d));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an object into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param obj the object to insert
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset is invalid.
|
||||
*/
|
||||
public ByteBuf insert(int offset, Object obj) {
|
||||
return insert(offset, String.valueOf(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a String into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param str the String to insert
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset is invalid.
|
||||
*/
|
||||
public ByteBuf insert(int offset, String str) {
|
||||
if ((offset < 0) || (offset > count)) {
|
||||
throw new StringIndexOutOfBoundsException();
|
||||
}
|
||||
int len = str.length();
|
||||
ensureCapacity(count + len);
|
||||
System.arraycopy(value, offset, value, offset + len, count - offset);
|
||||
for (int i=0 ; i<len ; i++) {
|
||||
value[offset++] = (byte) str.charAt(i);
|
||||
}
|
||||
count += len;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an array of bytes into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param str the characters to insert
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset is invalid.
|
||||
*/
|
||||
public ByteBuf insert(int offset, byte str[]) {
|
||||
if ((offset < 0) || (offset > count)) {
|
||||
throw new StringIndexOutOfBoundsException();
|
||||
}
|
||||
int len = str.length;
|
||||
ensureCapacity(count + len);
|
||||
System.arraycopy(value, offset, value, offset + len, count - offset);
|
||||
System.arraycopy(str, 0, value, offset, len);
|
||||
count += len;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a boolean into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param b the boolean to insert
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset is invalid.
|
||||
*/
|
||||
public ByteBuf insert(int offset, boolean b) {
|
||||
return insert(offset, String.valueOf(b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a byte into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param ch the character to insert
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset invalid.
|
||||
*/
|
||||
public ByteBuf insert(int offset, byte b) {
|
||||
ensureCapacity(count + 1);
|
||||
System.arraycopy(value, offset, value, offset + 1, count - offset);
|
||||
value[offset] = b;
|
||||
count += 1;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an integer into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param i the integer to insert
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset is invalid.
|
||||
*/
|
||||
public ByteBuf insert(int offset, int i) {
|
||||
return insert(offset, String.valueOf(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a long into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param l the long to insert
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset is invalid.
|
||||
*/
|
||||
public ByteBuf insert(int offset, long l) {
|
||||
return insert(offset, String.valueOf(l));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a float into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param f the float to insert
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset is invalid.
|
||||
*/
|
||||
public ByteBuf insert(int offset, float f) {
|
||||
return insert(offset, String.valueOf(f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a double into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param d the double to insert
|
||||
* @return the ByteBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset is invalid.
|
||||
*/
|
||||
public ByteBuf insert(int offset, double d) {
|
||||
return insert(offset, String.valueOf(d));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the order of the characters in the String buffer.
|
||||
*/
|
||||
public ByteBuf reverse() {
|
||||
int n = count - 1;
|
||||
for (int j = (n-1) >> 1; j >= 0; --j) {
|
||||
byte temp = value[j];
|
||||
value[j] = value[n - j];
|
||||
value[n - j] = temp;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts to a String representing the data in the buffer.
|
||||
*/
|
||||
public String toString() {
|
||||
return new String(value, 0, count);
|
||||
}
|
||||
|
||||
public byte[] toBytes() {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compares this ByteBuf to another ByteBuf. Returns true if the
|
||||
* other ByteBuf is equal to this ByteBuf; that is, has the same length
|
||||
* and the same characters in the same sequence. Upper case
|
||||
* characters are folded to lower case before they are compared.
|
||||
*
|
||||
* @param anotherString the String to compare this String against
|
||||
* @return true if the Strings are equal, ignoring case; false otherwise.
|
||||
*/
|
||||
public boolean equalsIgnoreCase(ByteBuf anotherString) {
|
||||
if ((anotherString != null) && (anotherString.count == count)) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
byte c1 = value[i];
|
||||
byte c2 = anotherString.value[i];
|
||||
if (c1 != c2) {
|
||||
// If characters don't match but case may be ignored,
|
||||
// try converting both characters to uppercase.
|
||||
// If the results match, then the comparison scan should
|
||||
// continue.
|
||||
char u1 = Character.toUpperCase((char) c1);
|
||||
char u2 = Character.toUpperCase((char) c2);
|
||||
if (u1 == u2)
|
||||
continue;
|
||||
|
||||
// Unfortunately, conversion to uppercase does not work properly
|
||||
// for the Georgian alphabet, which has strange rules about case
|
||||
// conversion. So we need to make one last check before
|
||||
// exiting.
|
||||
if (Character.toLowerCase(u1) == Character.toLowerCase(u2))
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean equals(Object aObject) {
|
||||
if (aObject != null) {
|
||||
if (aObject instanceof ByteBuf) {
|
||||
return equals((ByteBuf) aObject);
|
||||
} else if (aObject instanceof String) {
|
||||
return equals((String) aObject);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this ByteBuf to another ByteBuf. Returns true if the
|
||||
* other ByteBuf is equal to this ByteBuf; that is, has the same length
|
||||
* and the same characters in the same sequence.
|
||||
*
|
||||
* @param anotherString the String to compare this String against
|
||||
* @return true if the Strings are equal, ignoring case; false otherwise.
|
||||
*/
|
||||
public boolean equals(ByteBuf anotherString) {
|
||||
if ((anotherString != null) && (anotherString.count == count)) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
byte c1 = value[i];
|
||||
byte c2 = anotherString.value[i];
|
||||
if (c1 != c2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this ByteBuf to another String. Returns true if the
|
||||
* other String is equal to this ByteBuf; that is, has the same length
|
||||
* and the same characters in the same sequence. (No localization is done;
|
||||
* if the string doesn't contain 8-bit chars, it won't be equal to this
|
||||
* ByteBuf.)
|
||||
*
|
||||
* @param anotherString the String to compare this String against
|
||||
* @return true if the Strings are equal, ignoring case; false otherwise.
|
||||
*/
|
||||
public boolean equals(String anotherString) {
|
||||
if ((anotherString != null) && (anotherString.length() == count)) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
byte c1 = value[i];
|
||||
byte c2 = (byte) anotherString.charAt(i);
|
||||
if (c1 != c2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if two byte regions are equal.
|
||||
* <p>
|
||||
* If <code>toffset</code> or <code>ooffset</code> is negative, or
|
||||
* if <code>toffset</code>+<code>length</code> is greater than the
|
||||
* length of this ByteBuf, or if
|
||||
* <code>ooffset</code>+<code>length</code> is greater than the
|
||||
* length of the argument, then this method returns
|
||||
* <code>false</code>.
|
||||
*
|
||||
* @param toffset the starting offset of the subregion in this ByteBuf.
|
||||
* @param other the other bytes.
|
||||
* @param ooffset the starting offset of the subregion in the argument.
|
||||
* @param len the number of bytes to compare.
|
||||
* @return <code>true</code> if the specified subregion of this ByteBuf
|
||||
* exactly matches the specified subregion of the argument;
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean regionMatches(int toffset, byte other[],
|
||||
int ooffset, int len) {
|
||||
return regionMatches(false, toffset, other, ooffset, len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests if two byte regions are equal.
|
||||
* <p>
|
||||
* If <code>toffset</code> or <code>ooffset</code> is negative, or
|
||||
* if <code>toffset</code>+<code>length</code> is greater than the
|
||||
* length of this ByteBuf, or if
|
||||
* <code>ooffset</code>+<code>length</code> is greater than the
|
||||
* length of the argument, then this method returns
|
||||
* <code>false</code>.
|
||||
*
|
||||
* @param ignoreCase if <code>true</code>, ignore case when comparing
|
||||
* bytes (treating them as characters).
|
||||
* @param toffset the starting offset of the subregion in this
|
||||
* ByteBuf.
|
||||
* @param other the other bytes.
|
||||
* @param ooffset the starting offset of the subregion in the
|
||||
* argument.
|
||||
* @param len the number of bytes to compare.
|
||||
* @return <code>true</code> if the specified subregion of this ByteBuf
|
||||
* matches the specified subregion of the argument;
|
||||
* <code>false</code> otherwise. Whether the matching is exact
|
||||
* or case insensitive depends on the <code>ignoreCase</code>
|
||||
* argument.
|
||||
*/
|
||||
public boolean regionMatches(boolean ignoreCase,
|
||||
int toffset,
|
||||
byte other[],
|
||||
int ooffset,
|
||||
int len) {
|
||||
/* Lifted (and changed from char to byte) from java.lang.String. */
|
||||
byte ta[] = value;
|
||||
int to = toffset;
|
||||
int tlim = count;
|
||||
byte pa[] = other;
|
||||
int po = ooffset;
|
||||
// Note: toffset, ooffset, or len might be near -1>>>1.
|
||||
if ((ooffset < 0) || (toffset < 0) || (toffset > count - len) ||
|
||||
(ooffset > other.length - len)) {
|
||||
return false;
|
||||
}
|
||||
while (len-- > 0) {
|
||||
byte c1 = ta[to++];
|
||||
byte c2 = pa[po++];
|
||||
if (c1 == c2)
|
||||
continue;
|
||||
if (ignoreCase) {
|
||||
// If characters don't match but case may be ignored,
|
||||
// try converting both characters to uppercase.
|
||||
// If the results match, then the comparison scan should
|
||||
// continue.
|
||||
char u1 = Character.toUpperCase((char) c1);
|
||||
char u2 = Character.toUpperCase((char) c2);
|
||||
if (u1 == u2)
|
||||
continue;
|
||||
// Unfortunately, conversion to uppercase does not work properly
|
||||
// for the Georgian alphabet, which has strange rules about case
|
||||
// conversion. So we need to make one last check before
|
||||
// exiting.
|
||||
if (Character.toLowerCase(u1) == Character.toLowerCase(u2))
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public boolean regionMatches(int toffset, ByteBuf other,
|
||||
int ooffset, int len) {
|
||||
return regionMatches(false, toffset, other.value, ooffset, len);
|
||||
}
|
||||
|
||||
public boolean regionMatches(boolean ignoreCase,
|
||||
int toffset, ByteBuf other,
|
||||
int ooffset, int len) {
|
||||
return regionMatches(ignoreCase, toffset, other.value, ooffset, len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests if two byte regions are equal.
|
||||
* <p>
|
||||
* If <code>toffset</code> or <code>ooffset</code> is negative, or
|
||||
* if <code>toffset</code>+<code>length</code> is greater than the
|
||||
* length of this ByteBuf, or if
|
||||
* <code>ooffset</code>+<code>length</code> is greater than the
|
||||
* length of the argument, then this method returns
|
||||
* <code>false</code>.
|
||||
*
|
||||
* @param toffset the starting offset of the subregion in this ByteBuf.
|
||||
* @param other the other String.
|
||||
* @param ooffset the starting offset of the subregion in the argument.
|
||||
* @param len the number of bytes/characters to compare.
|
||||
* @return <code>true</code> if the specified subregion of this ByteBuf
|
||||
* exactly matches the specified subregion of the String argument;
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean regionMatches(int toffset, String other,
|
||||
int ooffset, int len) {
|
||||
return regionMatches(false, toffset, other, ooffset, len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests if two byte regions are equal.
|
||||
* <p>
|
||||
* If <code>toffset</code> or <code>ooffset</code> is negative, or
|
||||
* if <code>toffset</code>+<code>length</code> is greater than the
|
||||
* length of this ByteBuf, or if
|
||||
* <code>ooffset</code>+<code>length</code> is greater than the
|
||||
* length of the argument, then this method returns
|
||||
* <code>false</code>.
|
||||
*
|
||||
* @param ignoreCase if <code>true</code>, ignore case when comparing
|
||||
* bytes (treating them as characters).
|
||||
* @param toffset the starting offset of the subregion in this
|
||||
* ByteBuf.
|
||||
* @param other the other String.
|
||||
* @param ooffset the starting offset of the subregion in the
|
||||
* String argument.
|
||||
* @param len the number of bytes to compare.
|
||||
* @return <code>true</code> if the specified subregion of this ByteBuf
|
||||
* matches the specified subregion of the String argument;
|
||||
* <code>false</code> otherwise. Whether the matching is exact
|
||||
* or case insensitive depends on the <code>ignoreCase</code>
|
||||
* argument.
|
||||
*/
|
||||
public boolean regionMatches(boolean ignoreCase,
|
||||
int toffset,
|
||||
String other,
|
||||
int ooffset,
|
||||
int len) {
|
||||
/* Lifted (and changed from char to byte) from java.lang.String. */
|
||||
byte ta[] = value;
|
||||
int to = toffset;
|
||||
int tlim = count;
|
||||
int po = ooffset;
|
||||
// Note: toffset, ooffset, or len might be near -1>>>1.
|
||||
if ((ooffset < 0) || (toffset < 0) || (toffset > count - len) ||
|
||||
(ooffset > other.length() - len)) {
|
||||
return false;
|
||||
}
|
||||
while (len-- > 0) {
|
||||
byte c1 = ta[to++];
|
||||
byte c2 = (byte) other.charAt(po++);
|
||||
if (c1 == c2)
|
||||
continue;
|
||||
if (ignoreCase) {
|
||||
// If characters don't match but case may be ignored,
|
||||
// try converting both characters to uppercase.
|
||||
// If the results match, then the comparison scan should
|
||||
// continue.
|
||||
char u1 = Character.toUpperCase((char) c1);
|
||||
char u2 = Character.toUpperCase((char) c2);
|
||||
if (u1 == u2)
|
||||
continue;
|
||||
// Unfortunately, conversion to uppercase does not work properly
|
||||
// for the Georgian alphabet, which has strange rules about case
|
||||
// conversion. So we need to make one last check before
|
||||
// exiting.
|
||||
if (Character.toLowerCase(u1) == Character.toLowerCase(u2))
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public int indexOf(int ch) {
|
||||
return indexOf(ch, 0);
|
||||
}
|
||||
|
||||
public int indexOf(int ch, int fromIndex) {
|
||||
int max = count;
|
||||
byte v[] = value;
|
||||
|
||||
if (fromIndex < 0) {
|
||||
fromIndex = 0;
|
||||
} else if (fromIndex >= count) {
|
||||
// Note: fromIndex might be near -1>>>1.
|
||||
return -1;
|
||||
}
|
||||
for (int i = fromIndex ; i < max ; i++) {
|
||||
if (v[i] == ch) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void remove(int fromIndex) {
|
||||
remove(fromIndex, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove characters from the ByteBuf starting at fromIndex and up
|
||||
* to but not including toIndex. If toIndex is beyond the length of
|
||||
* the ByteBuf then it is automatically clamped to the end of the
|
||||
* ByteBuf. If fromIndex is out of range a StringIndexOutOfBoundsException
|
||||
* is thrown.
|
||||
*/
|
||||
public void remove(int fromIndex, int toIndex) {
|
||||
if ((fromIndex >= toIndex) || (fromIndex >= count)) {
|
||||
throw new StringIndexOutOfBoundsException(fromIndex);
|
||||
}
|
||||
if (toIndex > count) toIndex = count;
|
||||
if (toIndex == count) {
|
||||
count = fromIndex;
|
||||
return;
|
||||
}
|
||||
System.arraycopy(value, toIndex, value, fromIndex, count - toIndex);
|
||||
count -= toIndex - fromIndex;
|
||||
}
|
||||
|
||||
public int toInteger() throws NumberFormatException {
|
||||
int result = 0;
|
||||
int sign = 1;
|
||||
int i = 0;
|
||||
if (count == 0) {
|
||||
throw new NumberFormatException();
|
||||
}
|
||||
while (i < count - 1 && (value[i] <= ' ')) {
|
||||
i++;
|
||||
}
|
||||
if (value[i] == '-' && i < count - 1) {
|
||||
sign = -1;
|
||||
i++;
|
||||
}
|
||||
do {
|
||||
byte b = value[i];
|
||||
if (b >= '0' || b <= '9') {
|
||||
result = (result * 10) + (b - '0');
|
||||
} else {
|
||||
throw new NumberFormatException();
|
||||
}
|
||||
i++;
|
||||
} while (i < count && value[i] > ' ');
|
||||
while (i < count && value[i] < ' ') {
|
||||
i++;
|
||||
}
|
||||
if (i < count) {
|
||||
throw new NumberFormatException();
|
||||
}
|
||||
return result * sign;
|
||||
}
|
||||
|
||||
public ByteBuf trim() {
|
||||
int i=0;
|
||||
while (i < count && value[i] <= ' ') i++;
|
||||
if (i > 0) {
|
||||
count -= i;
|
||||
System.arraycopy(value, i, value, 0, count);
|
||||
}
|
||||
while (count > 0 && value[count-1] <= ' ') count--;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/** Write to the given output stream a detailed description of each
|
||||
byte in this buffer. */
|
||||
public void fullDump(PrintStream out) {
|
||||
fullDump(out, 0, count);
|
||||
}
|
||||
|
||||
/** Write to the given output stream a detailed description of the given
|
||||
bytes in this buffer. */
|
||||
public void fullDump(PrintStream out, int start, int end) {
|
||||
for (int i=start ; i<end ; i++) {
|
||||
out.write(value[i]);
|
||||
out.print("(" + ((int) value[i]) + ") ");
|
||||
}
|
||||
out.println("");
|
||||
}
|
||||
|
||||
/** Invokes InputStream.read(), appending the bytes to this Bytebuf.
|
||||
@return the number of bytes read, or -1 if eof.
|
||||
*/
|
||||
public int read(InputStream file, int max_bytes)
|
||||
throws IOException {
|
||||
ensureCapacity(count + max_bytes);
|
||||
int i = file.read(value, count, max_bytes);
|
||||
if (i > 0) count += i;
|
||||
return i;
|
||||
}
|
||||
|
||||
/** Invokes RandomAccessFile.read(), appending the bytes to this Bytebuf.
|
||||
(A RandomAccessFile is not an InputStream, because Java is a crock.)
|
||||
@return the number of bytes read, or -1 if eof.
|
||||
*/
|
||||
public int read(RandomAccessFile file, int max_bytes)
|
||||
throws IOException {
|
||||
ensureCapacity(count + max_bytes);
|
||||
int i = file.read(value, count, max_bytes);
|
||||
if (i > 0) count += i;
|
||||
return i;
|
||||
}
|
||||
|
||||
/** Writes the contents to the given output stream. */
|
||||
public void write(OutputStream out) throws IOException {
|
||||
out.write(value, 0, count);
|
||||
}
|
||||
|
||||
/** Writes the contents to the given RandomAccessFile. */
|
||||
public void write(RandomAccessFile out) throws IOException {
|
||||
out.write(value, 0, count);
|
||||
}
|
||||
|
||||
/** Creates a new InputStream whose content is this ByteBuf. Note that
|
||||
changing the ByteBuf can affect the stream; the data is <i>not</i>
|
||||
copied. */
|
||||
public InputStream makeInputStream() {
|
||||
return new ByteArrayInputStream(value, 0, count);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,346 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
/**
|
||||
* This class is stores data in a private ByteBuf appending new
|
||||
* data as needed, and returning line separated data.
|
||||
*/
|
||||
|
||||
public class ByteLineBuffer {
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private boolean buffer_full;
|
||||
private ByteBuf buffer;
|
||||
private ByteBuf outputeol;
|
||||
private ByteBuf inputeol;
|
||||
|
||||
/**
|
||||
* Constructs an empty ByteLineBuffer.
|
||||
*/
|
||||
|
||||
public ByteLineBuffer() {
|
||||
buffer = new ByteBuf();
|
||||
buffer_full = false;
|
||||
|
||||
if (DEBUG) {
|
||||
System.err.println("BLB " + hashCode() + ": created");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends data to the end of the internal ByteBuf.
|
||||
* @param buf data to append to internal buffer
|
||||
*/
|
||||
public void pushBytes(ByteBuf buf) {
|
||||
if (DEBUG) {
|
||||
System.err.print("BLB " + hashCode() + ": pushBytes(\"");
|
||||
byte b[] = buf.toBytes();
|
||||
for (int i = 0; i < buf.length(); i++)
|
||||
System.err.print((b[i] == '\r' ? "\\r" :
|
||||
b[i] == '\n' ? "\\n" :
|
||||
b[i] == '\t' ? "\\t" :
|
||||
b[i] == '"' ? "\\\"" :
|
||||
b[i] == '\\' ? "\\\\" :
|
||||
new String(b, i, 1)));
|
||||
System.err.print("\")\n");
|
||||
}
|
||||
buffer.append(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* indicates that the last piece of data is now present.
|
||||
*/
|
||||
|
||||
public void pushEOF() {
|
||||
if (DEBUG) {
|
||||
System.err.println("BLB " + hashCode() + ": pushEOF()");
|
||||
}
|
||||
buffer_full = true;
|
||||
}
|
||||
|
||||
/** Sets the EOL characters to look for in the incoming stream. Setting
|
||||
* this to be null will cause it to look for any of <CR>, <LF>, or <CRLF>.
|
||||
* Note that null (the default) could cause up to one extra to be held in
|
||||
* the buffer (in the case where the last byte read from the underlying
|
||||
* stream was <CR>, and no following byte (or EOF) has yet been read.)
|
||||
*/
|
||||
public void setInputEOL(ByteBuf buf) {
|
||||
Assert.Assertion(buf == null || buf.length() > 0);
|
||||
inputeol = buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* End of line characters <CR> & <LF> or any combination
|
||||
* will be replaced by this string if it is present. Setting
|
||||
* this to a zero length string will cause them to be stripped.
|
||||
* Setting this to null will cause the EOL characters to be passed
|
||||
* through unchanged (the default).
|
||||
* @param buf ByteBuf representing EOL replacement string
|
||||
*/
|
||||
|
||||
public void setOutputEOL(ByteBuf buf) {
|
||||
outputeol = buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ByteBuf with a line of data which was separated by
|
||||
* <CR><LF> or any combination. Holds the last line in the ByteBuf
|
||||
* until pushEOF() is called. If a ByteBuf containing data is sent in,
|
||||
* the data is removed.
|
||||
* @param buf single line of data in a ByteBuf
|
||||
* @return true if a line was retrieved, false if not
|
||||
*/
|
||||
|
||||
public boolean pullLine(ByteBuf buf) {
|
||||
int position;
|
||||
int buffer_length;
|
||||
byte value;
|
||||
// Remove any data that already exists in the buffer sent in
|
||||
buf.setLength(0);
|
||||
|
||||
if (buffer_full && buffer == null)
|
||||
return false;
|
||||
|
||||
buffer_length = buffer.length();
|
||||
|
||||
if (inputeol != null) {
|
||||
int last = buffer_length - inputeol.length() + 1;
|
||||
byte first = inputeol.byteAt(0);
|
||||
byte[] peekbuf = buffer.toBytes();
|
||||
for (position = 0 ; position < last ; position++) {
|
||||
if (peekbuf[position] == first) {
|
||||
boolean match = true;
|
||||
for (int j=inputeol.length() - 1 ; j>=1 ; j--) {
|
||||
if (peekbuf[position + j] != inputeol.byteAt(j)) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
buf.setLength(0);
|
||||
if (outputeol != null) {
|
||||
buf.append(peekbuf, 0, position);
|
||||
buf.append(outputeol);
|
||||
} else {
|
||||
buf.append(peekbuf, 0,
|
||||
position + inputeol.length());
|
||||
}
|
||||
buffer.remove(0, position + inputeol.length());
|
||||
|
||||
if (DEBUG) {
|
||||
System.err.print("BLB " + hashCode() +
|
||||
": EOL matched; returning: \"");
|
||||
byte b[] = buf.toBytes();
|
||||
for (int i = 0; i < buf.length(); i++)
|
||||
System.err.print((b[i] == '\r' ? "\\r" :
|
||||
b[i] == '\n' ? "\\n" :
|
||||
b[i] == '\t' ? "\\t" :
|
||||
b[i] == '"' ? "\\\"" :
|
||||
b[i] == '\\' ? "\\\\" :
|
||||
new String(b, i, 1)));
|
||||
System.err.print("\"\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// process the entire buffer, or until a newline character is hit
|
||||
for (position = 0; position < buffer_length; position++) {
|
||||
value = buffer.byteAt(position);
|
||||
if (value == '\n' || value == '\r') {
|
||||
|
||||
boolean ambiguous = true;
|
||||
|
||||
position++;
|
||||
// got a newline, pass it
|
||||
if (value == '\r' && position < buffer_length) {
|
||||
|
||||
if (DEBUG) {
|
||||
System.err.println("BLB " + hashCode() +
|
||||
": got \\r not at end of buffer");
|
||||
}
|
||||
|
||||
// if we have seen \r, and we know what character
|
||||
// lies after it, then there is no ambiguity:
|
||||
// the linebreak is "\r" or "\r\n", and we can
|
||||
// tell which it is.
|
||||
//
|
||||
ambiguous = false;
|
||||
|
||||
// if we are not replacing the EOL chars, return the
|
||||
// existing ones
|
||||
if (outputeol == null)
|
||||
buf.append(value);
|
||||
value = buffer.byteAt(position);
|
||||
if (value == '\n') {
|
||||
position++;
|
||||
if (outputeol == null)
|
||||
buf.append(value);
|
||||
}
|
||||
} else {
|
||||
|
||||
if (DEBUG) {
|
||||
if (value == '\r')
|
||||
System.err.println("BLB " + hashCode() +
|
||||
": got \\r at end of buffer");
|
||||
else
|
||||
System.err.println("BLB " + hashCode() +
|
||||
": got \\n without \\r");
|
||||
}
|
||||
|
||||
// If we have seen \n, then the linebreak is
|
||||
// unambiguously "\n". If we have seen \r, but we
|
||||
// don't know what character follows it (because
|
||||
// it happened to be at the end of the buffer) then
|
||||
// the linebreak is ambiguous ("\r" or "\r\n").
|
||||
//
|
||||
ambiguous = (value == '\r');
|
||||
|
||||
if (outputeol == null) {
|
||||
buf.append(value);
|
||||
}
|
||||
}
|
||||
|
||||
// if this is the last line in the buffer, and pushEOF()
|
||||
// hasn't been called, and the linebreak was ambiguous,
|
||||
// then wait for more data or a call to pushEOF() before
|
||||
// returning this line.
|
||||
//
|
||||
if (position == buffer_length &&
|
||||
!buffer_full &&
|
||||
ambiguous) {
|
||||
|
||||
if (DEBUG) {
|
||||
System.err.println("BLB " + hashCode() +
|
||||
": waiting for next line");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// remove the string from the internal ByteBuf
|
||||
buffer.remove(0,position);
|
||||
// if we have a replacement EOL string, use it
|
||||
if (outputeol != null)
|
||||
buf.append(outputeol);
|
||||
|
||||
if (DEBUG) {
|
||||
System.err.print("BLB " + hashCode() +
|
||||
": returning line: \"");
|
||||
byte b[] = buf.toBytes();
|
||||
for (int i = 0; i < buf.length(); i++)
|
||||
System.err.print((b[i] == '\r' ? "\\r" :
|
||||
b[i] == '\n' ? "\\n" :
|
||||
b[i] == '\t' ? "\\t" :
|
||||
b[i] == '"' ? "\\\"" :
|
||||
b[i] == '\\' ? "\\\\" :
|
||||
new String(b, i, 1)));
|
||||
System.err.print("\"\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
// append bytes to output ByteBuf
|
||||
buf.append(value);
|
||||
}
|
||||
}
|
||||
// process full buffer
|
||||
if (buffer_full && buffer_length > 0)
|
||||
{
|
||||
if (outputeol != null)
|
||||
buf.append(outputeol);
|
||||
buffer.remove(0,position);
|
||||
buffer.Recycle(buffer);
|
||||
buffer = null;
|
||||
|
||||
if (DEBUG) {
|
||||
System.err.print("BLB " + hashCode() +
|
||||
": at EOF; returning line: \"");
|
||||
byte b[] = buf.toBytes();
|
||||
for (int i = 0; i < buf.length(); i++)
|
||||
System.err.print((b[i] == '\r' ? "\\r" :
|
||||
b[i] == '\n' ? "\\n" :
|
||||
b[i] == '\t' ? "\\t" :
|
||||
b[i] == '"' ? "\\\"" :
|
||||
b[i] == '\\' ? "\\\\" :
|
||||
new String(b, i, 1)));
|
||||
System.err.print("\"\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// didn't get a string this time around.
|
||||
buf.setLength(0);
|
||||
|
||||
if (DEBUG) {
|
||||
System.err.println("BLB " + hashCode() +
|
||||
": don't have a line yet");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// public static void main(String args[]) {
|
||||
//
|
||||
// ByteLineBuffer blb = new ByteLineBuffer();
|
||||
// ByteBuf bb = new ByteBuf();
|
||||
// ByteBuf line_bytes = new ByteBuf(100);
|
||||
//
|
||||
// bb.setLength(0);
|
||||
// bb.append("from: jwz");
|
||||
// System.err.println("\npushed \"" + bb + "\""); blb.pushBytes(bb);
|
||||
// while(blb.pullLine(line_bytes)) {
|
||||
// System.err.println(" pulled \"" + line_bytes + "\"");
|
||||
// }
|
||||
//
|
||||
// bb.setLength(0);
|
||||
// bb.append("\r\n");
|
||||
// System.err.println("\npushed \"" + bb + "\""); blb.pushBytes(bb);
|
||||
// while(blb.pullLine(line_bytes)) {
|
||||
// System.err.println(" pulled \"" + line_bytes + "\"");
|
||||
// }
|
||||
//
|
||||
// bb.setLength(0);
|
||||
// bb.append("content-type: text/plain");
|
||||
// System.err.println("\npushed \"" + bb + "\""); blb.pushBytes(bb);
|
||||
// while(blb.pullLine(line_bytes)) {
|
||||
// System.err.println(" pulled \"" + line_bytes + "\"");
|
||||
// }
|
||||
//
|
||||
// bb.setLength(0);
|
||||
// bb.append("\r\n");
|
||||
// System.err.println("\npushed \"" + bb + "\""); blb.pushBytes(bb);
|
||||
// while(blb.pullLine(line_bytes)) {
|
||||
// System.err.println(" pulled \"" + line_bytes + "\"");
|
||||
// }
|
||||
//
|
||||
// bb.setLength(0);
|
||||
// System.err.println("\npushed EOF"); blb.pushEOF();
|
||||
// while(blb.pullLine(line_bytes)) {
|
||||
// System.err.println(" pulled \"" + line_bytes + "\"");
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Frank Tang <ftang@netscape.com>
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import sun.io.ByteToCharConverter;
|
||||
import java.lang.String;
|
||||
|
||||
/*
|
||||
* ByteToCharConverterEnumeration return a Enumeration of String which
|
||||
* represent ByteToCharConverter available in the classpath
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
public class ByteToCharConverterEnumeration extends PrefetchEnumeration {
|
||||
Enumeration fDelegate;
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
public ByteToCharConverterEnumeration()
|
||||
{
|
||||
fDelegate = new ClasspathEntryEnumeration("sun.io", "ByteToChar", ".class");
|
||||
}
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
protected boolean verify(Object obj)
|
||||
{
|
||||
try {
|
||||
ByteToCharConverter bc = ByteToCharConverter.getConverter((String)obj);
|
||||
return true;
|
||||
} catch (Exception e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
protected Object fetch()
|
||||
{
|
||||
for(; fDelegate.hasMoreElements(); )
|
||||
{
|
||||
Object candidcate = fDelegate.nextElement();
|
||||
if(verify(candidcate))
|
||||
{
|
||||
return candidcate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,409 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import calypso.util.TempFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.lang.OutOfMemoryError;
|
||||
|
||||
/** This class provides buffering for arbitrarily large streams of data.
|
||||
It is an <TT>OutputStream</TT>, so you just write the data you want to
|
||||
cache to it. Then, when you've written all of your data (and called
|
||||
<TT>close()</TT>) you can get the data back by calling
|
||||
<TT>makeInputStream()</TT>, which returns an <TT>InputStream</TT>.
|
||||
|
||||
<P> If you decide you don't want the data at all, you should call
|
||||
<TT>discardBuffer()</TT> as early as possible, to avoid having a temporary
|
||||
file stay around longer than necessary. It's not necessary to call
|
||||
<TT>discardBuffer()</TT> if you have called <TT>makeInputStream()</TT>;
|
||||
it is called automatically when that stream is closed. However, it is
|
||||
ok to call <TT>discardBuffer()</TT> than once.
|
||||
|
||||
<P> So, one conservative way of using this would be:
|
||||
<UL>
|
||||
<TT>CacheOutputStream output = new CacheOutputStream();</TT><BR>
|
||||
<TT>try {</TT><BR>
|
||||
<TT> </TT><I>... write bytes to `output' ...</I><BR>
|
||||
<TT> output.close();</TT><BR>
|
||||
<BR>
|
||||
<TT> InputStream input = output.makeInputStream();</TT><BR>
|
||||
<TT> try {</TT><BR>
|
||||
<TT> </TT><I>... read bytes from `input' ...</I>
|
||||
<BR>
|
||||
<TT> } finally {</TT><BR>
|
||||
<TT> input.close();</TT><BR>
|
||||
<TT> }</TT><BR>
|
||||
<BR>
|
||||
<TT>} finally {</TT><BR>
|
||||
<TT> output.discardBuffer();</TT><BR>
|
||||
<TT>}</TT></PRE></UL><P>
|
||||
|
||||
<DL><DT>Implementation:</DT><DD>
|
||||
<P> The bytes written to the stream are buffered in memory, until
|
||||
a size threshold is reached, or a memory-allocation error occurs.
|
||||
At that point, a temporary file is created, and buffering continues
|
||||
there. Therefore, files are not used for small objects; this ensures
|
||||
that buffering of small objects is fast, but buffering of arbitrarily
|
||||
large objects is possible.
|
||||
</DL>
|
||||
*/
|
||||
|
||||
public class CacheOutputStream extends OutputStream {
|
||||
|
||||
protected byte mem_cache[] = null;
|
||||
protected int mem_cache_fp = 0; // fill pointer
|
||||
protected int mem_cache_max_size = 0;
|
||||
protected double mem_cache_increment = 1.3; // expansion factor
|
||||
|
||||
protected Object bs_handle = null; // backing store
|
||||
protected OutputStream bs_stream = null;
|
||||
|
||||
|
||||
/** Creates a CacheOutputStream with default buffer sizes. */
|
||||
public CacheOutputStream() {
|
||||
this(64 * 1024);
|
||||
}
|
||||
|
||||
/** Creates a CacheOutputStream with the given maximum memory usage.
|
||||
If an attempt is made to buffer more than the specified number of
|
||||
bytes, then the memory buffer will be traded for a disk buffer.
|
||||
*/
|
||||
public CacheOutputStream(int max_resident_size) {
|
||||
this(0, max_resident_size);
|
||||
}
|
||||
|
||||
/** Creates a CacheOutputStream with the given initial memory buffer size,
|
||||
and given maximum memory usage.
|
||||
If an attempt is made to buffer more than the specified number of
|
||||
bytes, then the memory buffer will be traded for a disk buffer.
|
||||
*/
|
||||
public CacheOutputStream(int probable_size, int max_resident_size) {
|
||||
if (probable_size > max_resident_size)
|
||||
probable_size = 0;
|
||||
if (probable_size < 1024)
|
||||
probable_size = 1024;
|
||||
mem_cache = new byte[probable_size];
|
||||
mem_cache_max_size = max_resident_size;
|
||||
}
|
||||
|
||||
public void write(byte bytes[]) throws IOException {
|
||||
write (bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
public void write(byte bytes[], int start, int length) throws IOException {
|
||||
if (mem_cache != null)
|
||||
increaseCapacity(length);
|
||||
if (mem_cache != null) {
|
||||
System.arraycopy(bytes, start, mem_cache, mem_cache_fp, length);
|
||||
mem_cache_fp += length;
|
||||
} else {
|
||||
bs_stream.write(bytes, start, length);
|
||||
}
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
if (mem_cache != null)
|
||||
increaseCapacity(1);
|
||||
if (mem_cache != null) {
|
||||
mem_cache[mem_cache_fp++] = (byte) b;
|
||||
} else {
|
||||
bs_stream.write(b);
|
||||
}
|
||||
}
|
||||
|
||||
/** Indicate (only) that no more data will be written in to the buffer.
|
||||
After calling <TT>close()</TT>, one must eventually call either
|
||||
<TT>makeInputStream()</TT> or <TT>discardBuffer()</TT>.
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
if (bs_stream != null) {
|
||||
bs_stream.close();
|
||||
bs_stream = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
if (bs_stream != null)
|
||||
bs_stream.flush();
|
||||
}
|
||||
|
||||
|
||||
/** Ensure that there is room to write an additonal `count' bytes.
|
||||
If this would exceed the memory cache size, set up the disk cache.
|
||||
*/
|
||||
protected void increaseCapacity(int count) throws IOException {
|
||||
if (mem_cache == null) // already going to backing store...
|
||||
return;
|
||||
|
||||
int new_fp = mem_cache_fp + count;
|
||||
if (new_fp < mem_cache.length) // it still fits...
|
||||
return;
|
||||
if (new_fp < mem_cache_max_size) { // time to grow the array...
|
||||
growMemCache(count);
|
||||
} else { // time to switch to backing store...
|
||||
switchToBackingStore();
|
||||
}
|
||||
}
|
||||
|
||||
/** Assuming the memory cache is in use, expand the mem_cache to be
|
||||
able to hold an additional `count' bytes if necessary. */
|
||||
protected void growMemCache(int count) throws IOException {
|
||||
int new_fp = mem_cache_fp + count;
|
||||
int new_size = (int) (mem_cache.length * mem_cache_increment);
|
||||
if (new_size < mem_cache_fp + 1024)
|
||||
new_size = mem_cache_fp + 1024;
|
||||
if (new_size < new_fp)
|
||||
new_size = new_fp;
|
||||
|
||||
try {
|
||||
byte new_mem_cache[] = new byte[new_size];
|
||||
System.arraycopy(mem_cache, 0, new_mem_cache, 0, mem_cache_fp);
|
||||
mem_cache = new_mem_cache;
|
||||
} catch (OutOfMemoryError e) {
|
||||
// Couldn't allocate a new, bigger vector!
|
||||
// That's fine, we'll just switch to backing-store mode.
|
||||
switchToBackingStore();
|
||||
}
|
||||
}
|
||||
|
||||
/** Call this when you're done with this object.
|
||||
It's important that you call this if you're not planning on calling
|
||||
makeInputStream(); if you don't, a temp file could stay around longer
|
||||
than necessary.
|
||||
|
||||
<P> You must not use this CacheOutputStream object after having called
|
||||
discardBuffer().
|
||||
|
||||
<P> If you call makeInputStream(), you must not call discardBuffer()
|
||||
before you are finished with the returned stream.
|
||||
*/
|
||||
public synchronized void discardBuffer() {
|
||||
mem_cache = null;
|
||||
mem_cache_fp = 0;
|
||||
|
||||
if (bs_stream != null) {
|
||||
try {
|
||||
bs_stream.close();
|
||||
} catch (IOException e) {
|
||||
// just ignore it...
|
||||
}
|
||||
bs_stream = null;
|
||||
}
|
||||
|
||||
discardBackingStore();
|
||||
}
|
||||
|
||||
/** Returns an InputStream that returns the data previously written
|
||||
into this object. This may only be called once, and only after
|
||||
<TT>close()</TT> has been called. It is also important that the
|
||||
returned InputStream be closed when the caller is done with it;
|
||||
failure to do so could cause a temp file to stay around longer
|
||||
than necessary.
|
||||
*/
|
||||
public InputStream makeInputStream()
|
||||
throws IOException, FileNotFoundException {
|
||||
close();
|
||||
if (mem_cache != null) {
|
||||
byte[] v = mem_cache;
|
||||
int fp = mem_cache_fp;
|
||||
mem_cache = null;
|
||||
mem_cache_fp = 0;
|
||||
return new ByteArrayInputStream(v, 0, fp);
|
||||
} else if (bs_handle != null) {
|
||||
return createBackingStoreInputStream();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Calls discardBuffer(), in case this object was dropped without being
|
||||
properly shut down. */
|
||||
protected void finalize() {
|
||||
discardBuffer();
|
||||
}
|
||||
|
||||
|
||||
/** Assuming the memory cache is in use, switch to using the disk cache. */
|
||||
protected void switchToBackingStore() throws IOException {
|
||||
TempFile f = TempFile.TempName("");
|
||||
OutputStream s = f.create();
|
||||
if (mem_cache_fp > 0)
|
||||
s.write(mem_cache, 0, mem_cache_fp);
|
||||
|
||||
mem_cache = null;
|
||||
mem_cache_fp = 0;
|
||||
|
||||
bs_handle = f;
|
||||
bs_stream = s;
|
||||
}
|
||||
|
||||
/** Assuming backing-store is in use, delete the underlying temp file. */
|
||||
protected void discardBackingStore() {
|
||||
if (bs_handle != null) {
|
||||
TempFile f = (TempFile) bs_handle;
|
||||
f.delete();
|
||||
bs_handle = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Assuming backing-store is in use, creates an InputStream that reads
|
||||
from the underlying TempFile, and will call this.discardBuffer()
|
||||
when that InputStream reaches EOF. */
|
||||
protected InputStream createBackingStoreInputStream()
|
||||
throws FileNotFoundException {
|
||||
TempFile f = (TempFile) bs_handle;
|
||||
InputStream s = new BufferedInputStream(new FileInputStream(f.getName()));
|
||||
return new CacheInputStream(this, s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
public static final void main(String a[])
|
||||
throws FileNotFoundException, IOException {
|
||||
String s = "0123456789";
|
||||
String ss = "";
|
||||
while (s.length() < 1000)
|
||||
s = s + s;
|
||||
System.err.println("s len " + s.length());
|
||||
|
||||
CacheOutputStream output = new CacheOutputStream(0);
|
||||
try {
|
||||
|
||||
for (int ii = 0; ii < (80 * 1024); ii += s.length()) {
|
||||
System.err.println("writing " + s.length());
|
||||
output.write(s.getBytes());
|
||||
ss += s;
|
||||
}
|
||||
|
||||
output.close();
|
||||
|
||||
InputStream input = output.makeInputStream();
|
||||
try {
|
||||
byte b[] = new byte[4000];
|
||||
int i;
|
||||
String s2 = "";
|
||||
do {
|
||||
i = input.read(b);
|
||||
if (i >= 0) {
|
||||
System.err.println("read " + i);
|
||||
s2 = s2 + new String(b, 0, i);
|
||||
}
|
||||
} while (i >= 0);
|
||||
|
||||
if (ss.equals(s2))
|
||||
System.err.println("read correct bytes");
|
||||
else
|
||||
throw new Error("read wrong bytes");
|
||||
|
||||
} finally {
|
||||
input.close();
|
||||
}
|
||||
|
||||
} finally {
|
||||
output.discardBuffer();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** This is the private class that is used for reading data out of the
|
||||
file underlying a CacheOutputStream. This is used only when a file is
|
||||
being used for cacheing, not when the memory buffer is being used.
|
||||
Mainly this just passes the various InputStream methods along to
|
||||
the underlying file stream; but it adds one other thing, which is
|
||||
that as soon as the underlying file stream hits eof, the underlying
|
||||
file is deleted (by calling CacheOutputStream.discardBuffer().)
|
||||
*/
|
||||
class CacheInputStream extends InputStream {
|
||||
|
||||
protected CacheOutputStream stream_cache;
|
||||
protected InputStream stream;
|
||||
|
||||
CacheInputStream(CacheOutputStream sc, InputStream s) {
|
||||
stream_cache = sc;
|
||||
stream = s;
|
||||
}
|
||||
|
||||
public int available() throws IOException {
|
||||
return stream.available();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
stream.close();
|
||||
stream = null;
|
||||
discardBackingStore();
|
||||
}
|
||||
|
||||
public void mark(int i) {
|
||||
stream.mark(i);
|
||||
}
|
||||
|
||||
public boolean markSupported() {
|
||||
return stream.markSupported();
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
int result = stream.read();
|
||||
if (result < 0) discardBackingStore();
|
||||
return result;
|
||||
}
|
||||
|
||||
public int read(byte b[]) throws IOException {
|
||||
int result = stream.read(b);
|
||||
if (result < 0) discardBackingStore();
|
||||
return result;
|
||||
}
|
||||
|
||||
public int read(byte b[], int start, int length) throws IOException {
|
||||
int result = stream.read(b, start, length);
|
||||
if (result < 0) discardBackingStore();
|
||||
return result;
|
||||
}
|
||||
|
||||
public void reset() throws IOException {
|
||||
stream.reset();
|
||||
}
|
||||
|
||||
public long skip(long i) throws IOException {
|
||||
return stream.skip(i);
|
||||
}
|
||||
|
||||
protected synchronized void discardBackingStore() {
|
||||
if (stream_cache != null) {
|
||||
stream_cache.discardBuffer();
|
||||
stream_cache = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
discardBackingStore();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
public class CharArray
|
||||
{
|
||||
public static int indexOf(char[] str, int ch, int fromIndex)
|
||||
{
|
||||
int len = str.length;
|
||||
for (int i = fromIndex; i < len; i++)
|
||||
{
|
||||
if (str[i] == ch)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int indexOf(char[] str, int ch)
|
||||
{
|
||||
return indexOf(str, ch, 0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.text.*;
|
||||
|
||||
public final class CharArrayIterator implements CharacterIterator
|
||||
{
|
||||
private char[] fText;
|
||||
private int fStart;
|
||||
private int fEnd;
|
||||
private int fPosition;
|
||||
|
||||
public CharArrayIterator(char[] aText, int aStartOffset, int aLength)
|
||||
{
|
||||
int endOffset = aStartOffset + aLength;
|
||||
|
||||
if (aStartOffset < 0 || aLength < 0 ||
|
||||
(aStartOffset + aLength) > aText.length)
|
||||
throw new IllegalArgumentException("parameter out of range");
|
||||
|
||||
fText = aText;
|
||||
fStart = aStartOffset;
|
||||
fEnd = endOffset;
|
||||
fPosition = 0;
|
||||
}
|
||||
|
||||
public char first()
|
||||
{
|
||||
fPosition = fStart;
|
||||
return fText[fPosition];
|
||||
}
|
||||
|
||||
public char last()
|
||||
{
|
||||
fPosition = fEnd - 1;
|
||||
return fText[fPosition];
|
||||
}
|
||||
|
||||
public char current()
|
||||
{
|
||||
if (fPosition < fStart || fPosition >= fEnd)
|
||||
return CharacterIterator.DONE;
|
||||
|
||||
return fText[fPosition];
|
||||
}
|
||||
|
||||
public char next()
|
||||
{
|
||||
fPosition += 1;
|
||||
|
||||
if (fPosition >= fEnd)
|
||||
return CharacterIterator.DONE;
|
||||
|
||||
return fText[fPosition];
|
||||
}
|
||||
|
||||
public char previous()
|
||||
{
|
||||
fPosition -= 1;
|
||||
|
||||
if (fPosition < fStart)
|
||||
return CharacterIterator.DONE;
|
||||
|
||||
return fText[fPosition];
|
||||
}
|
||||
|
||||
public char setIndex(int aPosition)
|
||||
{
|
||||
if (aPosition < fStart || aPosition >= fEnd)
|
||||
throw new IllegalArgumentException("aPosition out of range");
|
||||
|
||||
fPosition = aPosition;
|
||||
return fText[fPosition];
|
||||
}
|
||||
|
||||
public int getBeginIndex()
|
||||
{
|
||||
return fStart;
|
||||
}
|
||||
|
||||
public int getEndIndex()
|
||||
{
|
||||
return fEnd;
|
||||
}
|
||||
|
||||
public int getIndex()
|
||||
{
|
||||
return fPosition;
|
||||
}
|
||||
|
||||
public Object clone()
|
||||
{
|
||||
try
|
||||
{
|
||||
CharArrayIterator other
|
||||
= (CharArrayIterator) super.clone();
|
||||
|
||||
return other;
|
||||
}
|
||||
catch (CloneNotSupportedException e)
|
||||
{
|
||||
throw new InternalError();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Frank Tang <ftang@netscape.com>
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
import java.util.Enumeration;
|
||||
import sun.io.CharToByteConverter;
|
||||
/*
|
||||
* CharToByteConverterEnumeration return a Enumeration of String
|
||||
* which represent available CharToByteConverter in the class path
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
|
||||
public class CharToByteConverterEnumeration extends PrefetchEnumeration {
|
||||
Enumeration fDelegate;
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
public CharToByteConverterEnumeration()
|
||||
{
|
||||
fDelegate = new ClasspathEntryEnumeration("sun.io", "CharToByte", ".class");
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
protected boolean verify(Object obj)
|
||||
{
|
||||
try {
|
||||
CharToByteConverter bc = CharToByteConverter.getConverter((String)obj);
|
||||
return true;
|
||||
} catch (Exception e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
protected Object fetch()
|
||||
{
|
||||
for(; fDelegate.hasMoreElements(); )
|
||||
{
|
||||
Object candidcate = fDelegate.nextElement();
|
||||
if(verify(candidcate))
|
||||
{
|
||||
return candidcate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,234 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Frank Tang <ftang@netscape.com>
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
import java.util.Enumeration;
|
||||
import java.io.File;
|
||||
import java.lang.String;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Hashtable;
|
||||
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
|
||||
abstract class FilterEnumeration extends PrefetchEnumeration {
|
||||
private Enumeration fDelegate;
|
||||
public FilterEnumeration( Enumeration en)
|
||||
{
|
||||
fDelegate = en;
|
||||
}
|
||||
abstract protected boolean verify(Object obj);
|
||||
protected Object fetch()
|
||||
{
|
||||
if(fDelegate.hasMoreElements()) {
|
||||
Object candidcate;
|
||||
for( candidcate = fDelegate.nextElement();
|
||||
fDelegate.hasMoreElements();
|
||||
candidcate = fDelegate.nextElement())
|
||||
{
|
||||
if(this.verify(candidcate))
|
||||
return candidcate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class ZipFileEnumeration implements Enumeration {
|
||||
class StringStartEndFilterEnumeration extends FilterEnumeration {
|
||||
private String fStart;
|
||||
private String fEnd;
|
||||
public StringStartEndFilterEnumeration(
|
||||
Enumeration en,
|
||||
String start,
|
||||
String end
|
||||
)
|
||||
{
|
||||
super(en);
|
||||
fStart = start;
|
||||
fEnd = end;
|
||||
}
|
||||
protected boolean verify(Object obj)
|
||||
{
|
||||
String str = (String)((ZipEntry) obj).getName();
|
||||
return str.startsWith(fStart) && str.endsWith(fEnd);
|
||||
}
|
||||
}
|
||||
private Enumeration fDelegate;
|
||||
private String fPrefix;
|
||||
private String fPostfix;
|
||||
|
||||
public ZipFileEnumeration (
|
||||
File zip ,String pkg, String prefix, String postfix)
|
||||
{
|
||||
fPrefix = pkg.replace('.', '/') + '/' + prefix;
|
||||
fPostfix = postfix;
|
||||
try {
|
||||
ZipFile zf = new ZipFile(zip);
|
||||
fDelegate = new
|
||||
StringStartEndFilterEnumeration(
|
||||
zf.entries(),
|
||||
fPrefix,
|
||||
fPostfix
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
System.out.println(e); // For Debug only
|
||||
fDelegate = null;
|
||||
}
|
||||
}
|
||||
public boolean hasMoreElements()
|
||||
{
|
||||
return ((fDelegate != null) &&
|
||||
fDelegate.hasMoreElements());
|
||||
}
|
||||
public Object nextElement()
|
||||
{
|
||||
if(fDelegate == null)
|
||||
return null;
|
||||
String current = (String)((ZipEntry) fDelegate.nextElement()).getName();
|
||||
return current.substring(
|
||||
fPrefix.length(),
|
||||
(current.length() - fPostfix.length()));
|
||||
}
|
||||
}
|
||||
class DirectoryEnumeration extends PrefetchEnumeration {
|
||||
private String fList[] = null;
|
||||
private String fPrefix;
|
||||
private String fPostfix;
|
||||
private int fIdx = 0;
|
||||
|
||||
public DirectoryEnumeration (
|
||||
File dir ,String pkg, String prefix, String postfix)
|
||||
{
|
||||
fPrefix = prefix;
|
||||
fPostfix = postfix;
|
||||
File realdir = new File(dir, pkg.replace('.',File.separatorChar));
|
||||
if(realdir.exists() && realdir.isDirectory() && realdir.canRead())
|
||||
{
|
||||
fList = realdir.list();
|
||||
fIdx = -1;
|
||||
}
|
||||
}
|
||||
protected Object fetch()
|
||||
{
|
||||
if(fList != null)
|
||||
{
|
||||
for(fIdx++ ; fIdx < fList.length; fIdx++)
|
||||
{
|
||||
if( fList[fIdx].startsWith( fPrefix ) &&
|
||||
fList[fIdx].endsWith( fPostfix ) )
|
||||
{
|
||||
return fList[fIdx].substring(
|
||||
fPrefix.length(),
|
||||
(fList[fIdx].length() - fPostfix.length()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public class ClasspathEntryEnumeration extends PrefetchEnumeration {
|
||||
|
||||
private String fPkg;
|
||||
private String fPrefix;
|
||||
private String fPostfix;
|
||||
private Enumeration fEntryEnumeration;
|
||||
private Enumeration fPathEnumeration;
|
||||
private Hashtable cache;
|
||||
|
||||
/*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
public ClasspathEntryEnumeration( String pkg, String prefix, String postfix)
|
||||
{
|
||||
fPrefix = prefix;
|
||||
fPostfix = postfix;
|
||||
fPkg = pkg;
|
||||
fFetch = null;
|
||||
cache = new Hashtable(20);
|
||||
|
||||
fPathEnumeration = new StringTokenizer(
|
||||
System.getProperty("java.class.path"),
|
||||
File.pathSeparator);
|
||||
fEntryEnumeration = null;
|
||||
}
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
protected Object fetch()
|
||||
{
|
||||
|
||||
if((fEntryEnumeration != null) &&
|
||||
fEntryEnumeration.hasMoreElements())
|
||||
{
|
||||
Object candidcate = fEntryEnumeration.nextElement();
|
||||
|
||||
if(cache.get(candidcate) != null)
|
||||
return fetch(); // have been report once, try next
|
||||
cache.put(candidcate, candidcate);
|
||||
return candidcate;
|
||||
|
||||
}
|
||||
if(fPathEnumeration.hasMoreElements())
|
||||
{
|
||||
String newPathEntry = (String) fPathEnumeration.nextElement();
|
||||
File newPathBase = new File(newPathEntry);
|
||||
if(newPathBase.exists() && newPathBase.canRead())
|
||||
{
|
||||
if(newPathBase.isDirectory())
|
||||
{
|
||||
fEntryEnumeration =
|
||||
new DirectoryEnumeration (
|
||||
newPathBase, fPkg, fPrefix, fPostfix);
|
||||
}
|
||||
else
|
||||
{
|
||||
fEntryEnumeration =
|
||||
new ZipFileEnumeration (
|
||||
newPathBase, fPkg, fPrefix, fPostfix);
|
||||
}
|
||||
}
|
||||
return fetch();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
/** This interface is the thing used by QSort to compare two objects.
|
||||
@see QSort
|
||||
*/
|
||||
public interface Comparer {
|
||||
/** Compare two objects for sorting.
|
||||
Should return negative if A < B, positive if A > B, else 0.
|
||||
*/
|
||||
int compare(Object a, Object b);
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.*;
|
||||
import java.net.*;
|
||||
|
||||
public class ConfigUtils {
|
||||
|
||||
private static String gFileSeparator = System.getProperty("file.separator");
|
||||
private static String gUserDir = System.getProperty("user.dir");
|
||||
|
||||
/**
|
||||
* This is the standardized place for getting a list of URLs which
|
||||
* you should search, in order, when trying to locate a resource
|
||||
* which may be overridden by external files. This is used, at time
|
||||
* of writing, by the Configuration system, which looks for things
|
||||
* within packages, but first looks for external files which will
|
||||
* effectively replace the package resources.
|
||||
* aBaseClass is necessary if aLocation refers to a resource
|
||||
* (which it normally will). In this case, we will need a class loader.
|
||||
* supplied by aBaseClass.
|
||||
* @param aLocation The resource path for locating the resource in
|
||||
* its default location, a package. Use a full
|
||||
* name, like "/netscape/shell/imp/ShellConfig.xml".
|
||||
* Use a slash for the path separator character.
|
||||
* @param aBaseClass A base class using the same classloader as
|
||||
* aLocation. That is, a class from the same .jar file.
|
||||
* Can be null if aLocation is a simple local system file.
|
||||
* @return an enumeration of URLs to try, in order
|
||||
*/
|
||||
public static final Enumeration fileSearchURLs(
|
||||
String aLocation,
|
||||
Class aBaseClass) {
|
||||
|
||||
URL url;
|
||||
int nameIndex = aLocation.lastIndexOf('/');
|
||||
String fileName = nameIndex >= 0 && nameIndex < aLocation.length()-1 ?
|
||||
aLocation.substring(nameIndex+1) : aLocation;
|
||||
Vector urls = new Vector(2,2);
|
||||
|
||||
// first, try to find a file with the given name in the user directory.
|
||||
try {
|
||||
// can user.dir be off the net (not a file URL) on a Network Computer?
|
||||
urls.addElement(new URL("file", "", gUserDir + gFileSeparator + fileName));
|
||||
} catch (MalformedURLException mue) {
|
||||
}
|
||||
url = aBaseClass != null ? aBaseClass.getResource(aLocation) :
|
||||
ClassLoader.getSystemResource(aLocation);
|
||||
if (url != null)
|
||||
urls.addElement(url);
|
||||
|
||||
return urls.elements();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
/**
|
||||
* Like Integer except the value is mutable
|
||||
*/
|
||||
public class Counter {
|
||||
protected int fValue;
|
||||
|
||||
public Counter(int i) {
|
||||
fValue = i;
|
||||
}
|
||||
|
||||
public int intValue() {
|
||||
return fValue;
|
||||
}
|
||||
|
||||
public void increment() {
|
||||
++fValue;
|
||||
}
|
||||
|
||||
public void decrement() {
|
||||
--fValue;
|
||||
}
|
||||
|
||||
public void setValue(int aNewValue) {
|
||||
fValue = aNewValue;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.Hashtable;
|
||||
import java.lang.ClassLoader;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
public class DataExtension {
|
||||
private Hashtable cache = null;
|
||||
private boolean caseInsensitive = false;
|
||||
private String prefix;
|
||||
private String postfix;
|
||||
private String[] urls;
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
public DataExtension ( String prefix, String postfix, boolean caseInsensitive, String[] fallbackURLs)
|
||||
{
|
||||
cache = new Hashtable(20) ;
|
||||
this.prefix = prefix;
|
||||
this.postfix = postfix;
|
||||
this.caseInsensitive = caseInsensitive;
|
||||
this.urls = fallbackURLs;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
public String getValue (String key, String Name)
|
||||
{
|
||||
if(caseInsensitive)
|
||||
key = URLEncoder.encode(key.toLowerCase()).toLowerCase();
|
||||
Hashtable group = null;
|
||||
group = getGroup(key);
|
||||
if(group != null)
|
||||
return (String) group.get(Name);
|
||||
else
|
||||
return (String) null;
|
||||
}
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
synchronized private Hashtable getGroup(String key)
|
||||
{
|
||||
Object lookup = null;
|
||||
lookup = cache.get(key);
|
||||
|
||||
if(lookup != null)
|
||||
return (Hashtable) lookup;
|
||||
|
||||
try {
|
||||
Properties p = new Properties();
|
||||
String name = prefix + key + postfix;
|
||||
p.load( ClassLoader.getSystemResourceAsStream( name ) );
|
||||
cache.put(key, p);
|
||||
return (Hashtable) p;
|
||||
} catch(Exception e) {
|
||||
/* TO DO */
|
||||
/* do urls fallback here */
|
||||
return (Hashtable) null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
|
@ -0,0 +1,56 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class DefaultPreferences extends Properties {
|
||||
|
||||
public DefaultPreferences() {
|
||||
}
|
||||
|
||||
public void pref(String property, String value) {
|
||||
put(property, value);
|
||||
}
|
||||
|
||||
public void pref(String property, int value) {
|
||||
put(property, (String)(""+value));
|
||||
}
|
||||
|
||||
public void pref(String property, boolean value) {
|
||||
put(property, (String)(""+value));
|
||||
}
|
||||
|
||||
public void pref(String property, char value) {
|
||||
put(property, (String)(""+value));
|
||||
}
|
||||
|
||||
public void pref(String property, long value) {
|
||||
put(property, (String)(""+value));
|
||||
}
|
||||
|
||||
public void pref(String property, float value) {
|
||||
put(property, (String)(""+value));
|
||||
}
|
||||
|
||||
public void pref(String property, double value) {
|
||||
put(property, (String)(""+value));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This takes a bunch of enumerators, and runs through them all, in the order
|
||||
* given.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Vector;
|
||||
|
||||
public class EnumerationEnumerator implements Enumeration {
|
||||
Vector enums;
|
||||
int cur;
|
||||
|
||||
public EnumerationEnumerator() {
|
||||
enums = new Vector();
|
||||
cur = 0;
|
||||
}
|
||||
|
||||
public void add(Enumeration e) {
|
||||
enums.addElement(e);
|
||||
}
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
for (int i=cur ; i<enums.size() ; i++) {
|
||||
if (((Enumeration) enums.elementAt(i)).hasMoreElements()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object nextElement() throws NoSuchElementException {
|
||||
do {
|
||||
Enumeration e = ((Enumeration) enums.elementAt(cur));
|
||||
if (e.hasMoreElements()) {
|
||||
return e.nextElement();
|
||||
}
|
||||
cur++;
|
||||
} while (cur < enums.size());
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,592 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
// Hashtable.java
|
||||
// By Ned Etcode
|
||||
// Stolen and folded into calypso by Peter Linss
|
||||
// Copyright 1995, 1996, 1997 Netscape Communications Corp. All rights reserved.
|
||||
|
||||
// Each entry in the table can be in one of three states:
|
||||
// 1. Empty -> hashCodes[index] == EMPTY
|
||||
// 2. Removed -> hashCodes[index] == REMOVED
|
||||
// 3. Filled -> keys[index] != null
|
||||
|
||||
// You must call Hashtable.hash() to get the real hash code for this table.
|
||||
|
||||
// There needs to be a way to call Object.hashCode() directly when you want
|
||||
// to do identity hashing. ALERT!
|
||||
|
||||
/** Object subclass that implements a hash table.
|
||||
* @note 1.0 toString() prints as formatted text
|
||||
*/
|
||||
abstract class HashtableBase implements Cloneable
|
||||
{
|
||||
/** For the multiplicative hash, choose the golden ratio:
|
||||
* <pre>
|
||||
* A = ((sqrt(5) - 1) / 2) * (1 << 32)
|
||||
* </pre>
|
||||
* ala Knuth...
|
||||
*/
|
||||
static final int A = 0x9e3779b9;
|
||||
|
||||
/** We use EMPTY and REMOVED as special markers in the table. If some
|
||||
* poor object returns one of these two values as their hashCode, it
|
||||
* is wacked to DEFAULT.
|
||||
*/
|
||||
static final int EMPTY = 0;
|
||||
static final int REMOVED = 1;
|
||||
static final int DEFAULT = 2;
|
||||
|
||||
int count;
|
||||
int totalCount;
|
||||
int shift;
|
||||
int capacity;
|
||||
int indexMask;
|
||||
|
||||
int hashCodes[];
|
||||
Object keys[];
|
||||
Object elements[];
|
||||
|
||||
/** Constructs an empty Hashtable. The Hashtable will grow on demand
|
||||
* as more elements are added.
|
||||
*/
|
||||
HashtableBase () {
|
||||
super();
|
||||
shift = 32 - 3 + 1;
|
||||
}
|
||||
|
||||
/** Constructs a Hashtable capable of holding at least
|
||||
* <b>initialCapacity</b> elements before needing to grow.
|
||||
*/
|
||||
HashtableBase (int aInitialCapacity) {
|
||||
this();
|
||||
|
||||
if (aInitialCapacity < 0)
|
||||
throw new IllegalArgumentException("aInitialCapacity must be > 0");
|
||||
|
||||
grow (aInitialCapacity);
|
||||
}
|
||||
|
||||
/** Creates a shallow copy of the Hashtable. The table itself is cloned,
|
||||
* but none of the keys or elements are copied.
|
||||
*/
|
||||
public Object clone() {
|
||||
int len;
|
||||
HashtableBase newTable;
|
||||
|
||||
try {
|
||||
newTable = (HashtableBase)super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new InternalError(
|
||||
"Error in clone(). This shouldn't happen.");
|
||||
}
|
||||
|
||||
// If there is nothing in the table, then we cloned to make sure the
|
||||
// class was preserved, but just null everything out except for shift,
|
||||
// which implies the default initial capacity.
|
||||
|
||||
if (count == 0) {
|
||||
newTable.shift = 32 - 3 + 1;
|
||||
newTable.totalCount = 0;
|
||||
newTable.capacity = 0;
|
||||
newTable.indexMask = 0;
|
||||
newTable.hashCodes = null;
|
||||
newTable.keys = null;
|
||||
newTable.elements = null;
|
||||
|
||||
return newTable;
|
||||
}
|
||||
|
||||
len = hashCodes.length;
|
||||
newTable.hashCodes = new int[len];
|
||||
newTable.keys = new Object[len];
|
||||
newTable.elements = new Object[len];
|
||||
|
||||
System.arraycopy(hashCodes, 0, newTable.hashCodes, 0, len);
|
||||
System.arraycopy(keys, 0, newTable.keys, 0, len);
|
||||
System.arraycopy(elements, 0, newTable.elements, 0, len);
|
||||
|
||||
return newTable;
|
||||
}
|
||||
|
||||
/** Returns the number of elements in the Hashtable.
|
||||
*/
|
||||
public int count() {
|
||||
return count;
|
||||
}
|
||||
|
||||
/** Returns the number of elements in the Hashtable.
|
||||
*/
|
||||
public int size() {
|
||||
return count;
|
||||
}
|
||||
|
||||
/** Returns <b>true</b> if there are no elements in the Hashtable.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return (count == 0);
|
||||
}
|
||||
|
||||
/** Returns an Enumeration of the Hashtable's keys.
|
||||
* @see #elements
|
||||
*/
|
||||
public Enumeration keys() {
|
||||
return new HashtableEnumerator(this, true);
|
||||
}
|
||||
|
||||
/** Returns an Enumeration of the Hashtable's elements.
|
||||
* @see #keys
|
||||
*/
|
||||
public Enumeration elements() {
|
||||
return new HashtableEnumerator(this, false);
|
||||
}
|
||||
|
||||
/** Returns a Vector containing the Hashtable's keys.
|
||||
*/
|
||||
public Vector keysVector() {
|
||||
int i, vectCount;
|
||||
Object key;
|
||||
Vector vect;
|
||||
|
||||
if (count == 0)
|
||||
return new Vector();
|
||||
|
||||
vect = new Vector(count);
|
||||
vectCount = 0;
|
||||
|
||||
for (i = 0; i < keys.length && vectCount < count; i++) {
|
||||
key = keys[i];
|
||||
if (key != null) {
|
||||
vect.addElement(key);
|
||||
vectCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return vect;
|
||||
}
|
||||
|
||||
/** Returns a Vector containing the Hashtable's elements.
|
||||
*/
|
||||
public Vector elementsVector() {
|
||||
int i, vectCount;
|
||||
Object element;
|
||||
Vector vect;
|
||||
|
||||
if (count == 0)
|
||||
return new Vector();
|
||||
|
||||
vect = new Vector(count);
|
||||
vectCount = 0;
|
||||
|
||||
for (i = 0; i < elements.length && vectCount < count; i++) {
|
||||
element = elements[i];
|
||||
if (element != null) {
|
||||
vect.addElement(element);
|
||||
vectCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return vect;
|
||||
}
|
||||
|
||||
/** Returns an Object array containing the Hashtable's keys.
|
||||
*/
|
||||
|
||||
int getKeysArray (Object[] aArray) {
|
||||
int i, arrayCount;
|
||||
Object key;
|
||||
|
||||
arrayCount = 0;
|
||||
|
||||
for (i = 0; i < keys.length && arrayCount < count; i++) {
|
||||
key = keys[i];
|
||||
if (key != null) {
|
||||
aArray[arrayCount++] = key;
|
||||
}
|
||||
}
|
||||
|
||||
return arrayCount;
|
||||
}
|
||||
|
||||
/** Returns an Object array containing the Hashtable's elements.
|
||||
*/
|
||||
int getElementsArray (Object[] aArray) {
|
||||
int i, arrayCount;
|
||||
Object element;
|
||||
|
||||
arrayCount = 0;
|
||||
|
||||
for (i = 0; i < elements.length && arrayCount < count; i++) {
|
||||
element = elements[i];
|
||||
if (element != null) {
|
||||
aArray[arrayCount++] = element;
|
||||
}
|
||||
}
|
||||
|
||||
return arrayCount;
|
||||
}
|
||||
|
||||
/** Returns <b>true</b> if the Hashtable contains the element. This method
|
||||
* is slow -- O(n) -- because it must scan the table searching for the
|
||||
* element.
|
||||
*/
|
||||
boolean containsElement (Object aElement) {
|
||||
int i;
|
||||
Object tmp;
|
||||
|
||||
// We need to short-circuit here since the data arrays may not have
|
||||
// been allocated yet.
|
||||
|
||||
if (count == 0)
|
||||
return false;
|
||||
|
||||
if (aElement == null)
|
||||
throw new NullPointerException();
|
||||
|
||||
if (elements == null)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < elements.length; i++) {
|
||||
tmp = elements[i];
|
||||
if (tmp != null && aElement.equals (tmp))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** Removes <b>key</b> and the element associated with it from the
|
||||
* Hashtable. Returns the element associated with <b>key</b>, or
|
||||
* <b>null</b> if <b>key</b> was not present.
|
||||
*/
|
||||
Object removeKey (Object aKey) {
|
||||
int index;
|
||||
Object oldValue;
|
||||
|
||||
// We need to short-circuit here since the data arrays may not have
|
||||
// been allocated yet.
|
||||
|
||||
if (count == 0)
|
||||
return null;
|
||||
|
||||
index = tableIndexFor(aKey, hash(aKey));
|
||||
oldValue = elements[index];
|
||||
if (oldValue == null)
|
||||
return null;
|
||||
|
||||
count--;
|
||||
hashCodes[index] = REMOVED;
|
||||
keys[index] = null;
|
||||
elements[index] = null;
|
||||
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
/** Places the <b>key</b>/<b>element</b> pair in the Hashtable. Neither
|
||||
* <b>key</b> nor <b>element</b> may be <b>null</b>. Returns the old
|
||||
* element associated with <b>key</b>, or <b>null</b> if the <b>key</b>
|
||||
* was not present.
|
||||
*/
|
||||
Object put (Object aKey, Object aElement) {
|
||||
int index, hash;
|
||||
Object oldValue;
|
||||
|
||||
if (aElement == null)
|
||||
throw new NullPointerException();
|
||||
|
||||
// Since we delay allocating the data arrays until we actually need
|
||||
// them, check to make sure they exist before attempting to put
|
||||
// something in them.
|
||||
|
||||
if (hashCodes == null)
|
||||
grow();
|
||||
|
||||
hash = hash(aKey);
|
||||
index = tableIndexFor(aKey, hash);
|
||||
oldValue = elements[index];
|
||||
|
||||
// If the total number of occupied slots (either with a real element or
|
||||
// a removed marker) gets too big, grow the table.
|
||||
|
||||
if (oldValue == null) {
|
||||
if (hashCodes[index] == EMPTY) {
|
||||
if (totalCount >= capacity) {
|
||||
grow();
|
||||
return put(aKey, aElement);
|
||||
}
|
||||
totalCount++;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
hashCodes[index] = hash;
|
||||
keys[index] = aKey;
|
||||
elements[index] = aElement;
|
||||
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
/** We preclude the hashCodes EMPTY and REMOVED because we use them to
|
||||
* indicate empty and previously filled slots in the table. All the
|
||||
* Hashtable code should go through here and not call hashCode()
|
||||
* directly on the key.
|
||||
*/
|
||||
int hash(Object aKey) {
|
||||
int hash;
|
||||
|
||||
// On sparc it appears that the last 3 bits of Object.hashCode() are
|
||||
// insignificant! ALERT!
|
||||
|
||||
hash = aKey.hashCode();
|
||||
if (hash == EMPTY || hash == REMOVED)
|
||||
hash = DEFAULT;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/** Primitive method used internally to find slots in the
|
||||
* table. If the key is present in the table, this method will return the
|
||||
* index
|
||||
* under which it is stored. If the key is not present, then this
|
||||
* method will return the index under which it can be put. The caller
|
||||
* must look at the hashCode at that index to differentiate between
|
||||
* the two possibilities.
|
||||
*/
|
||||
int tableIndexFor(Object aKey, int aHash) {
|
||||
int product, testHash, index, step, removedIndex, probeCount;
|
||||
|
||||
product = aHash * A;
|
||||
index = product >>> shift;
|
||||
|
||||
// Probe the first slot in the table. We keep track of the first
|
||||
// index where we found a REMOVED marker so we can return that index
|
||||
// as the first available slot if the key is not already in the table.
|
||||
|
||||
testHash = hashCodes[index];
|
||||
|
||||
if (testHash == aHash) {
|
||||
if (aKey.equals (keys[index]))
|
||||
return index;
|
||||
removedIndex = -1;
|
||||
} else if (testHash == EMPTY)
|
||||
return index;
|
||||
else if (testHash == REMOVED)
|
||||
removedIndex = index;
|
||||
else
|
||||
removedIndex = -1;
|
||||
|
||||
// Our first probe has failed, so now we need to start looking
|
||||
// elsewhere in the table.
|
||||
|
||||
step = ((product >>> (2 * shift - 32)) & indexMask) | 1;
|
||||
probeCount = 1;
|
||||
|
||||
do {
|
||||
probeCount++;
|
||||
index = (index + step) & indexMask;
|
||||
|
||||
testHash = hashCodes[index];
|
||||
|
||||
if (testHash == aHash) {
|
||||
if (aKey.equals (keys[index]))
|
||||
return index;
|
||||
} else if (testHash == EMPTY) {
|
||||
if (removedIndex < 0)
|
||||
return index;
|
||||
else
|
||||
return removedIndex;
|
||||
} else if (testHash == REMOVED && removedIndex == -1)
|
||||
removedIndex = index;
|
||||
|
||||
} while (probeCount <= totalCount);
|
||||
|
||||
// Something very bad has happened.
|
||||
|
||||
throw new Error ("Hashtable overflow");
|
||||
}
|
||||
|
||||
/** Grows the table to accommodate at least capacity number of elements.
|
||||
*/
|
||||
private void grow (int aCapacity) {
|
||||
int tableSize, power;
|
||||
|
||||
// Find the lowest power of 2 size for the table which will allow
|
||||
// us to insert initialCapacity number of objects before having to
|
||||
// grow.
|
||||
|
||||
tableSize = (aCapacity * 4) / 3;
|
||||
|
||||
power = 3;
|
||||
while ((1 << power) < tableSize)
|
||||
power++;
|
||||
|
||||
// Once shift is set, then grow() will do the right thing when
|
||||
// called.
|
||||
|
||||
shift = 32 - power + 1;
|
||||
grow();
|
||||
}
|
||||
|
||||
/** Grows the table by a factor of 2 (or creates it if necessary). All
|
||||
* the REMOVED markers go away and the elements are rehashed into the
|
||||
* bigger table.
|
||||
*/
|
||||
protected void grow() {
|
||||
int i, index, hash, power, oldHashCodes[];
|
||||
Object key, oldKeys[], oldValues[];
|
||||
|
||||
// The table size needs to be a power of two, and it should double
|
||||
// when it grows. We grow when we are more than 3/4 full.
|
||||
|
||||
shift--;
|
||||
power = 32 - shift;
|
||||
indexMask = (1 << power) - 1;
|
||||
capacity = (3 * (1 << power)) / 4;
|
||||
|
||||
oldHashCodes = hashCodes;
|
||||
oldKeys = keys;
|
||||
oldValues = elements;
|
||||
|
||||
hashCodes = new int[1 << power];
|
||||
keys = new Object[1 << power];
|
||||
elements = new Object[1 << power];
|
||||
|
||||
// Reinsert the old elements into the new table if there are any. Be
|
||||
// sure to reset the counts and increment them as the old entries are
|
||||
// put back in the table.
|
||||
|
||||
totalCount = 0;
|
||||
|
||||
if (count > 0) {
|
||||
count = 0;
|
||||
|
||||
for (i = 0; i < oldHashCodes.length; i++) {
|
||||
key = oldKeys[i];
|
||||
|
||||
if (key != null) {
|
||||
hash = oldHashCodes[i];
|
||||
index = tableIndexFor(key, hash);
|
||||
|
||||
hashCodes[index] = hash;
|
||||
keys[index] = key;
|
||||
elements[index] = oldValues[i];
|
||||
|
||||
count++;
|
||||
totalCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Removes all keys and elements from the Hashtable.
|
||||
*/
|
||||
public void clear() {
|
||||
int i;
|
||||
|
||||
if (hashCodes == null)
|
||||
return;
|
||||
|
||||
for (i = 0; i < hashCodes.length; i++) {
|
||||
hashCodes[i] = EMPTY;
|
||||
keys[i] = null;
|
||||
elements[i] = null;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
totalCount = 0;
|
||||
}
|
||||
|
||||
/** Returns a string serialization of the Hashtable using the
|
||||
* Serializer.
|
||||
* @see Serializer
|
||||
*/
|
||||
public String toString ()
|
||||
{
|
||||
if ((count == 0) || (keys == null))
|
||||
return "{empty}";
|
||||
|
||||
StringBuf buffer = new StringBuf ("{\n");
|
||||
|
||||
Object key;
|
||||
Object element;
|
||||
for (int index = 0; index < elements.length; index++)
|
||||
{
|
||||
key = keys[index];
|
||||
if (null != key)
|
||||
{
|
||||
element = elements[index];
|
||||
buffer.append (" " + key + " = " + element);
|
||||
}
|
||||
}
|
||||
buffer.append ("}");
|
||||
|
||||
return buffer.toString ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class HashtableEnumerator implements Enumeration {
|
||||
boolean keyEnum;
|
||||
int index;
|
||||
int returnedCount;
|
||||
HashtableBase table;
|
||||
|
||||
HashtableEnumerator(HashtableBase table, boolean keyEnum) {
|
||||
super();
|
||||
this.table = table;
|
||||
this.keyEnum = keyEnum;
|
||||
returnedCount = 0;
|
||||
|
||||
if (table.keys != null)
|
||||
index = table.keys.length;
|
||||
else
|
||||
index = 0;
|
||||
}
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
if (returnedCount < table.count)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object nextElement() {
|
||||
index--;
|
||||
|
||||
while (index >= 0 && table.elements[index] == null)
|
||||
index--;
|
||||
|
||||
if (index < 0 || returnedCount >= table.count)
|
||||
throw new NoSuchElementException();
|
||||
|
||||
returnedCount++;
|
||||
|
||||
if (keyEnum)
|
||||
return table.keys[index];
|
||||
|
||||
return table.elements[index];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,340 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
class ElementEnumeration
|
||||
implements Enumeration
|
||||
{
|
||||
private int fIndex;
|
||||
private HashtableLite fTable;
|
||||
|
||||
public ElementEnumeration (HashtableLite theTable)
|
||||
{
|
||||
fTable = theTable;
|
||||
}
|
||||
|
||||
public boolean hasMoreElements ()
|
||||
{
|
||||
if (fIndex < fTable.fCount) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
public Object nextElement ()
|
||||
{
|
||||
return fTable.fItems[(fIndex++*2) + 1];
|
||||
}
|
||||
}
|
||||
|
||||
class KeyEnumeration
|
||||
implements Enumeration
|
||||
{
|
||||
private int fIndex;
|
||||
private HashtableLite fTable;
|
||||
|
||||
KeyEnumeration (HashtableLite theTable)
|
||||
{
|
||||
fTable = theTable;
|
||||
}
|
||||
|
||||
public boolean hasMoreElements ()
|
||||
{
|
||||
if (fIndex < fTable.fCount) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
public Object nextElement ()
|
||||
{
|
||||
return fTable.fItems[fIndex++*2];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility class to avoid the pain (and memory bloat)
|
||||
* of making lots of small hashtables. A real HashTable
|
||||
* isn't created until the number of elements grows past
|
||||
* a certain number (defined internally to HashtableLite).
|
||||
*
|
||||
* It sure would have been nice if Hashtables were an interface.
|
||||
*
|
||||
* @author thom 08-19-97 2:06am
|
||||
*/
|
||||
|
||||
public class HashtableLite extends Object
|
||||
implements java.lang.Cloneable
|
||||
{
|
||||
int fCount;
|
||||
Object fItems[]; // [0] = key, [1] = item, etc
|
||||
AtomHashtable fRealTable;
|
||||
|
||||
private static final int maxItems = 4;
|
||||
|
||||
public HashtableLite ()
|
||||
{
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
fCount = 0;
|
||||
fRealTable = null;
|
||||
fItems = null;
|
||||
}
|
||||
|
||||
public Object clone()
|
||||
{
|
||||
HashtableLite theClone = new HashtableLite();
|
||||
|
||||
if (fRealTable != null)
|
||||
{
|
||||
theClone.fRealTable = (AtomHashtable) fRealTable.clone();
|
||||
}
|
||||
else if (fCount > 0)
|
||||
{
|
||||
theClone.fItems = (Object[]) fItems.clone();
|
||||
theClone.fCount = fCount;
|
||||
}
|
||||
return theClone;
|
||||
}
|
||||
|
||||
public boolean contains (Object item)
|
||||
{
|
||||
if (fCount > 0)
|
||||
{
|
||||
for (int i = 0; i < fCount; ++i )
|
||||
if (fItems[(i*2) + 1] == item)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
if (fRealTable != null)
|
||||
return fRealTable.contains (item);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean containsKey (Atom key)
|
||||
{
|
||||
if (fCount > 0)
|
||||
{
|
||||
for (int i = 0; i < fCount; ++i )
|
||||
if (fItems[i*2] == key)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
if (fRealTable != null)
|
||||
return fRealTable.containsKey (key);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int count ()
|
||||
{
|
||||
if (fRealTable != null) return fRealTable.count();
|
||||
return fCount;
|
||||
}
|
||||
|
||||
public Enumeration elements()
|
||||
{
|
||||
if (fCount > 0)
|
||||
return new ElementEnumeration (this);
|
||||
|
||||
if (fRealTable != null)
|
||||
return fRealTable.elements();
|
||||
|
||||
return NullEnumeration.kInstance;
|
||||
}
|
||||
|
||||
public Object[] elementsArray()
|
||||
{
|
||||
if (fRealTable != null)
|
||||
return fRealTable.elementsArray();
|
||||
Assert.NotYetImplemented("Arg");
|
||||
return null;
|
||||
}
|
||||
|
||||
public Vector elementsVector ()
|
||||
{
|
||||
if (fRealTable != null)
|
||||
return fRealTable.elementsVector();
|
||||
Assert.NotYetImplemented("Arg");
|
||||
return null;
|
||||
}
|
||||
|
||||
/*public void decode (Decoder aDecoder)
|
||||
{
|
||||
if (fRealTable != null)
|
||||
fRealTable.decode(aDecoder);
|
||||
|
||||
}
|
||||
|
||||
public void describeClassInfo (ClassInfo theInfo)
|
||||
{
|
||||
if (fRealTable != null)
|
||||
fRealTable.describeClassInfo(theInfo);
|
||||
|
||||
}
|
||||
|
||||
public void encode (Encoder anEncoder)
|
||||
{
|
||||
if (fRealTable != null)
|
||||
fRealTable.encode (anEncoder);
|
||||
|
||||
}
|
||||
|
||||
public void finishDecoding()
|
||||
{
|
||||
if (fRealTable != null)
|
||||
fRealTable.finishDecoding();
|
||||
|
||||
}*/
|
||||
|
||||
public Object get (Atom key)
|
||||
{
|
||||
if (fCount > 0)
|
||||
{
|
||||
for (int i = 0; i < fCount; ++i )
|
||||
if (fItems[i*2] == key)
|
||||
return fItems[(i*2) + 1];
|
||||
return null;
|
||||
}
|
||||
else if (fRealTable != null)
|
||||
return fRealTable.get (key);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isEmpty ()
|
||||
{
|
||||
if (fCount == 0 && fRealTable == null)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object put (Atom key, Object item)
|
||||
{
|
||||
if (fRealTable != null)
|
||||
{
|
||||
return fRealTable.put (key, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fItems == null) fItems = new Object[maxItems*2];
|
||||
|
||||
// is it already in the table?
|
||||
|
||||
for (int i = 0; i < fCount; ++i )
|
||||
if (fItems[i*2] == key)
|
||||
{
|
||||
Object oldItem = fItems[(i*2) + 1];
|
||||
fItems[(i*2) + 1] = item;
|
||||
return oldItem;
|
||||
}
|
||||
|
||||
// no, must add new key/item pair
|
||||
|
||||
if (fCount == maxItems) // spill over to real hashtable?
|
||||
{
|
||||
fRealTable = new AtomHashtable();
|
||||
|
||||
for (int i = 0; i < fCount; ++i )
|
||||
fRealTable.put (fItems[i*2], fItems[(i*2) + 1]);
|
||||
|
||||
fItems = null;
|
||||
fCount = 0;
|
||||
|
||||
return fRealTable.put (key, item);
|
||||
}
|
||||
|
||||
// simple case, add the item
|
||||
|
||||
fItems[fCount*2] = key;
|
||||
fItems[(fCount*2) + 1] = item;
|
||||
++fCount;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Enumeration keys ()
|
||||
{
|
||||
if (fRealTable != null)
|
||||
return fRealTable.keys();
|
||||
|
||||
if (fCount > 0) return new KeyEnumeration (this);
|
||||
|
||||
return NullEnumeration.kInstance;
|
||||
}
|
||||
|
||||
public Atom[] keysArray()
|
||||
{
|
||||
if (fRealTable != null)
|
||||
return fRealTable.keysArray();
|
||||
Assert.NotYetImplemented("Arg");
|
||||
return null;
|
||||
}
|
||||
|
||||
public Vector keysVector()
|
||||
{
|
||||
if (fRealTable != null)
|
||||
return fRealTable.keysVector();
|
||||
Assert.NotYetImplemented("Arg");
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object remove (Atom key)
|
||||
{
|
||||
if (fRealTable != null)
|
||||
return fRealTable.remove(key);
|
||||
|
||||
if (fCount > 0)
|
||||
for (int i = 0; i < fCount; ++i )
|
||||
if (fItems[i*2] == key)
|
||||
{
|
||||
Object oldItem = fItems[i*2 + 1];
|
||||
|
||||
--fCount;
|
||||
for (int j = i; j < fCount - 1; ++j)
|
||||
{
|
||||
fItems[(j*2) + 1] = fItems[((j+1)*2) + 1];
|
||||
fItems[ j*2] = fItems[ (j+1)*2];
|
||||
}
|
||||
return oldItem;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
if (fRealTable != null)
|
||||
return fRealTable.size();
|
||||
|
||||
return fCount;
|
||||
}
|
||||
|
||||
public String toString ()
|
||||
{
|
||||
if (fRealTable != null)
|
||||
return fRealTable.toString();
|
||||
|
||||
return "Hi, I'm a hack";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Static recycler class for java.util.Hashtable
|
||||
*
|
||||
* @author psl 04-23-97 6:48pm
|
||||
*/
|
||||
public final class HashtableRecycler
|
||||
{
|
||||
static Recycler gRecycler;
|
||||
|
||||
/**
|
||||
* Get one
|
||||
*
|
||||
* @return
|
||||
* @exception
|
||||
* @author psl 04-23-97 6:49pm
|
||||
*/
|
||||
public static synchronized Hashtable Alloc ()
|
||||
{
|
||||
Hashtable result = null;
|
||||
|
||||
if (null != gRecycler)
|
||||
result = (Hashtable)gRecycler.getRecycledObject ();
|
||||
if (null == result)
|
||||
result = new Hashtable ();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get one with an initial size
|
||||
* <I>since the growth mechanism is private (for now) a recycled
|
||||
* table won't really grow to capacity</I>
|
||||
*
|
||||
* @param aCapacity desired initial capacity
|
||||
* @return
|
||||
* @exception
|
||||
* @author psl 04-23-97 6:49pm
|
||||
*/
|
||||
public static synchronized Hashtable Alloc (int aCapacity)
|
||||
{
|
||||
Hashtable result = null;
|
||||
|
||||
if (null != gRecycler)
|
||||
result = (Hashtable)gRecycler.getRecycledObject ();
|
||||
if (null == result)
|
||||
result = new Hashtable (aCapacity);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recycle a hashtable
|
||||
* (it will be cleared by the recycler)
|
||||
*
|
||||
* @param aTable table to be recycled
|
||||
* @return
|
||||
* @exception
|
||||
* @author psl 04-23-97 6:50pm
|
||||
*/
|
||||
public static synchronized void Recycle (Hashtable aTable)
|
||||
{
|
||||
if (null == gRecycler)
|
||||
gRecycler = new Recycler ();
|
||||
aTable.clear ();
|
||||
gRecycler.recycle (aTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty the recycler, it's earth day
|
||||
*
|
||||
* @param
|
||||
* @return
|
||||
* @exception
|
||||
* @author psl 04-21-97 4:29pm
|
||||
*/
|
||||
static synchronized public void EmptyRecycler ()
|
||||
{
|
||||
if (null != gRecycler)
|
||||
gRecycler.empty ();
|
||||
}
|
||||
|
||||
/**
|
||||
* finalize class for unloading
|
||||
*
|
||||
* @param
|
||||
* @return
|
||||
* @exception
|
||||
* @author psl 04-21-97 4:29pm
|
||||
*/
|
||||
static void classFinalize () throws Throwable
|
||||
{
|
||||
// Poof! Now we are unloadable even though we have a static
|
||||
// variable.
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,294 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
/**
|
||||
* An identifier mapper. This provides a 1-1 map between strings and
|
||||
* integers where the strings are unique within the map.
|
||||
*/
|
||||
public class IDMap {
|
||||
private Object[] fKeys;
|
||||
private int[] fHashCodes;
|
||||
private int[] fValues;
|
||||
private String[] fStrings;
|
||||
private int fNumStrings;
|
||||
private int fShift;
|
||||
private int fIndexMask;
|
||||
private int fCount;
|
||||
private int fCapacity;
|
||||
|
||||
public IDMap() {
|
||||
fShift = 32 - 3 + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a string, find an id for it. If the string is already
|
||||
* present return the old id. Otherwise allocate a new one.
|
||||
*/
|
||||
public synchronized int stringToID(String aStr) {
|
||||
if (fHashCodes == null) {
|
||||
grow();
|
||||
}
|
||||
int hash = hashCodeForString(aStr); // hashCodeFor(aStr);
|
||||
int slot = tableIndexFor(aStr, hash);
|
||||
if (fHashCodes[slot] == EMPTY) {
|
||||
// If the total number of occupied slots gets too big, grow the
|
||||
// table.
|
||||
if (fCount >= fCapacity) {
|
||||
grow();
|
||||
return stringToID(aStr);
|
||||
}
|
||||
fCount++;
|
||||
fHashCodes[slot] = hash;
|
||||
fKeys[slot] = aStr;
|
||||
fValues[slot] = addString(aStr);
|
||||
}
|
||||
return fValues[slot];
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a StringBuf, find an id for it. If the string is already
|
||||
* present return the old id. Otherwise allocate a new one.
|
||||
*/
|
||||
public synchronized int stringBufToID(StringBuf aStrBuf) {
|
||||
if (fHashCodes == null) {
|
||||
return( stringToID( aStrBuf.toString() ) );
|
||||
}
|
||||
int hash = hashCodeForStringBuf(aStrBuf);
|
||||
int slot = tableIndexFor(aStrBuf, hash);
|
||||
if (fHashCodes[slot] == EMPTY) {
|
||||
// not found, insert it.
|
||||
return( stringToID( aStrBuf.toString() ) );
|
||||
}
|
||||
return fValues[slot];
|
||||
}
|
||||
|
||||
public synchronized String stringBufToString(StringBuf aStrBuf) {
|
||||
int id = stringBufToID(aStrBuf);
|
||||
return fStrings[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* If the argument string is already present in the map return the
|
||||
* original string object. Otherwise, allocate a new id and return
|
||||
* the argument string.
|
||||
*/
|
||||
public synchronized String stringToString(String aStr) {
|
||||
int id = stringToID(aStr);
|
||||
return fStrings[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an id, return the string it maps to.
|
||||
*/
|
||||
public String idToString(int aID) {
|
||||
if ((aID < 0) || (aID >= fNumStrings)) {
|
||||
throw new IllegalArgumentException("invalid id: " + aID);
|
||||
}
|
||||
return fStrings[aID];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add string to the end of the internal strings array. Return the
|
||||
* index in the array.
|
||||
*/
|
||||
private int addString(String aString) {
|
||||
int rv = fNumStrings;
|
||||
if (fStrings == null) {
|
||||
fStrings = new String[4];
|
||||
} else if (rv == fStrings.length) {
|
||||
int newLen = rv;
|
||||
if (newLen < 32) {
|
||||
// Double the size of small tables
|
||||
newLen = newLen * 2;
|
||||
} else {
|
||||
// Grow by 20% for larger tables
|
||||
newLen = (int) (newLen * 1.2f);
|
||||
}
|
||||
String[] ns = new String[newLen];
|
||||
System.arraycopy(fStrings, 0, ns, 0, rv);
|
||||
fStrings = ns;
|
||||
}
|
||||
fStrings[fNumStrings++] = aString;
|
||||
return rv;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Hashtable code lifted from the netscape.util package; retargeted
|
||||
// to use int's as the value's; also removed the "REMOVE" code.
|
||||
|
||||
/** For the multiplicative hash, choose the golden ratio:
|
||||
* <pre>
|
||||
* A = ((sqrt(5) - 1) / 2) * (1 << 32)
|
||||
* </pre>
|
||||
* ala Knuth...
|
||||
*/
|
||||
private static final int A = 0x9e3779b9;
|
||||
|
||||
/**
|
||||
* We use EMPTY and REMOVED as special markers in the table. If some
|
||||
* poor object returns one of these two values as their hashCode, it
|
||||
* is wacked to DEFAULT.
|
||||
*/
|
||||
private static final int EMPTY = 0;
|
||||
private static final int DEFAULT = 2;
|
||||
|
||||
/**
|
||||
* Provide hashcode for a given key
|
||||
*/
|
||||
/* private final int hashCodeFor(Object aKey) {
|
||||
int hash = aKey.hashCode();
|
||||
if (hash == EMPTY)
|
||||
hash = DEFAULT;
|
||||
return hash;
|
||||
}
|
||||
*/
|
||||
// We want StringBuf and String have the same hash code, if
|
||||
// they contain the same string. Therefor, we need to do our
|
||||
// own hash code for String.
|
||||
private final int hashCodeForString(String str ) {
|
||||
int h = 0;
|
||||
int len = str.length();
|
||||
if (len < 16) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
h = (h * 37) + str.charAt(i);
|
||||
}
|
||||
} else {
|
||||
// only sample some characters
|
||||
int skip = len / 8;
|
||||
for (int i = len, off = 0 ; i > 0; i -= skip, off += skip) {
|
||||
h = (h * 39) + str.charAt(off);
|
||||
}
|
||||
}
|
||||
if (h == EMPTY)
|
||||
h = DEFAULT;
|
||||
return h;
|
||||
}
|
||||
|
||||
private final int hashCodeForStringBuf(StringBuf strBuf) {
|
||||
int h = 0;
|
||||
int len = strBuf.length();
|
||||
if (len < 16) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
h = (h * 37) + strBuf.charAt(i);
|
||||
}
|
||||
} else {
|
||||
// only sample some characters
|
||||
int skip = len / 8;
|
||||
for (int i = len, off = 0 ; i > 0; i -= skip, off += skip) {
|
||||
h = (h * 39) + strBuf.charAt(off);
|
||||
}
|
||||
}
|
||||
if (h == EMPTY)
|
||||
h = DEFAULT;
|
||||
return h;
|
||||
}
|
||||
|
||||
private final boolean keysAreEqual(Object aKey1, Object aKey2) {
|
||||
// It is emportant to use aKey1's equals because aKey1 can be
|
||||
// a String or StringBuf.
|
||||
return aKey1.equals (aKey2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Primitive method used internally to find slots in the table. If
|
||||
* the key is present in the table, this method will return the
|
||||
* index under which it is stored. If the key is not present, then
|
||||
* this method will return the index under which it can be put. The
|
||||
* caller must look at the hashCode at that index to differentiate
|
||||
* between the two possibilities.
|
||||
*/
|
||||
private int tableIndexFor(Object aKey, int aHash) {
|
||||
// Probe the first slot in the table. We keep track of the first
|
||||
// index where we found a REMOVED marker so we can return that index
|
||||
// as the first available slot if the key is not already in the table.
|
||||
int product = aHash * A;
|
||||
int index = product >>> fShift;
|
||||
int testHash = fHashCodes[index];
|
||||
if (testHash == aHash) {
|
||||
if (keysAreEqual(aKey, fKeys[index]))
|
||||
return index;
|
||||
} else if (testHash == EMPTY)
|
||||
return index;
|
||||
|
||||
// Our first probe has failed, so now we need to start looking
|
||||
// elsewhere in the table.
|
||||
int step = ((product >>> (2 * fShift - 32)) & fIndexMask) | 1;
|
||||
int probeCount = 1;
|
||||
do {
|
||||
probeCount++;
|
||||
index = (index + step) & fIndexMask;
|
||||
|
||||
testHash = fHashCodes[index];
|
||||
|
||||
if (testHash == aHash) {
|
||||
if (keysAreEqual(aKey, fKeys[index]))
|
||||
return index;
|
||||
} else if (testHash == EMPTY) {
|
||||
return index;
|
||||
}
|
||||
} while (probeCount <= fCount);
|
||||
|
||||
// Something very bad has happened.
|
||||
throw new Error ("Hashtable overflow");
|
||||
}
|
||||
|
||||
/**
|
||||
* Grows the table by a factor of 2 (or creates it if necessary). All
|
||||
* the REMOVED markers go away and the elements are rehashed into the
|
||||
* bigger table.
|
||||
*/
|
||||
private void grow() {
|
||||
// The table size needs to be a power of two, and it should double
|
||||
// when it grows. We grow when we are more than 3/4 full.
|
||||
fShift--;
|
||||
int power = 32 - fShift;
|
||||
fIndexMask = (1 << power) - 1;
|
||||
fCapacity = (3 * (1 << power)) / 4;
|
||||
|
||||
int[] oldHashCodes = fHashCodes;
|
||||
Object[] oldKeys = fKeys;
|
||||
int[] oldValues = fValues;
|
||||
|
||||
fHashCodes = new int[1 << power];
|
||||
fKeys = new Object[1 << power];
|
||||
fValues = new int[1 << power];
|
||||
|
||||
// Reinsert the old elements into the new table if there are any. Be
|
||||
// sure to reset the counts and increment them as the old entries are
|
||||
// put back in the table.
|
||||
if (fCount > 0) {
|
||||
fCount = 0;
|
||||
for (int i = 0; i < oldHashCodes.length; i++) {
|
||||
Object key = oldKeys[i];
|
||||
if (key != null) {
|
||||
int hash = oldHashCodes[i];
|
||||
int index = tableIndexFor(key, hash);
|
||||
|
||||
fHashCodes[index] = hash;
|
||||
fKeys[index] = key;
|
||||
fValues[index] = oldValues[i];
|
||||
|
||||
fCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import calypso.util.ByteBuf;
|
||||
import calypso.util.ByteLineBuffer;
|
||||
|
||||
public class LineBufferingInputStream extends FilterInputStream {
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final int CAPACITY = 1024;
|
||||
|
||||
ByteBuf curline = new ByteBuf();
|
||||
ByteBuf inbuf = new ByteBuf(CAPACITY);
|
||||
ByteLineBuffer linebuf = new ByteLineBuffer();
|
||||
boolean eof = false;
|
||||
|
||||
public LineBufferingInputStream(InputStream s) {
|
||||
super(s);
|
||||
|
||||
if (DEBUG) {
|
||||
System.err.println("LBIS " + hashCode() + ": created for " + s);
|
||||
}
|
||||
}
|
||||
|
||||
/** Reads bytes into a portion of an array. This method will block
|
||||
until some input is available.
|
||||
<P>
|
||||
The returned data will not be more than one line long: that is, there
|
||||
will be at most one linebreak (CR, LF, or CRLF) and if it is present,
|
||||
it will be at the end.
|
||||
<P>
|
||||
If the next line available to be read is smaller than `length',
|
||||
then the first `length' bytes of that line will be returned, and
|
||||
the remainder of the bytes on that line will be available for
|
||||
subsequent reads.
|
||||
|
||||
@return the total number of bytes read into the buffer, or -1 if
|
||||
there is no more data because the end of the stream has
|
||||
been reached.
|
||||
*/
|
||||
public int read(byte[] buf, int start, int length) throws IOException {
|
||||
|
||||
if (DEBUG) {
|
||||
System.err.println("LBIS " + hashCode() + ": read(byte[], " +
|
||||
start + ", " + length + ")");
|
||||
}
|
||||
|
||||
|
||||
if (length <= 0) return length;
|
||||
int curlen = curline.length();
|
||||
if (curlen == 0) {
|
||||
if (eof) return -1;
|
||||
while (!linebuf.pullLine(curline)) {
|
||||
inbuf.setLength(CAPACITY);
|
||||
int inlen = in.read(inbuf.toBytes(), 0, CAPACITY);
|
||||
|
||||
if (inlen <= 0) {
|
||||
eof = true;
|
||||
linebuf.pushEOF();
|
||||
linebuf.pullLine(curline); // Try for the last gasp...
|
||||
break;
|
||||
}
|
||||
|
||||
inbuf.setLength(inlen);
|
||||
|
||||
if (DEBUG) {
|
||||
byte b[] = inbuf.toBytes();
|
||||
System.err.print("LBIS " + hashCode() + ": read " + inlen +
|
||||
" bytes: ");
|
||||
for (int i = 0; i < inlen; i++)
|
||||
System.err.print((b[i] == '\r' ? "\\r" :
|
||||
b[i] == '\n' ? "\\n" :
|
||||
b[i] == '\t' ? "\\t" :
|
||||
b[i] == '\\' ? "\\\\" :
|
||||
new String(b, i, 1)));
|
||||
System.err.print("\n");
|
||||
}
|
||||
|
||||
linebuf.pushBytes(inbuf);
|
||||
}
|
||||
|
||||
curlen = curline.length();
|
||||
if (curlen == 0) return -1;
|
||||
}
|
||||
int result = length;
|
||||
if (result > curlen) result = curlen;
|
||||
curline.getBytes(0, result, buf, start);
|
||||
curlen -= result;
|
||||
curline.remove(0, result);
|
||||
|
||||
if (DEBUG) {
|
||||
byte b[] = curline.toBytes();
|
||||
System.err.print("LBIS " + hashCode() + ": read line: ");
|
||||
for (int i = 0; i < curline.length(); i++)
|
||||
System.err.print((b[i] == '\r' ? "\\r" :
|
||||
b[i] == '\n' ? "\\n" :
|
||||
b[i] == '\t' ? "\\t" :
|
||||
b[i] == '\\' ? "\\\\" :
|
||||
new String(b, i, 1)));
|
||||
System.err.print("\n");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public int read(byte[] buf) throws IOException {
|
||||
return read(buf, 0, buf.length);
|
||||
}
|
||||
|
||||
byte[] singlebyte;
|
||||
public int read() throws IOException {
|
||||
if (singlebyte == null) singlebyte = new byte[1];
|
||||
if (read(singlebyte, 0, 1) <= 0) return -1;
|
||||
return singlebyte[0];
|
||||
}
|
||||
|
||||
public long skip(long n) {
|
||||
return 0; // Feh.
|
||||
}
|
||||
|
||||
public boolean markSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
|
||||
if (DEBUG) {
|
||||
System.err.println("LBIS " + hashCode() + ": closed");
|
||||
}
|
||||
|
||||
curline = null;
|
||||
inbuf = null;
|
||||
linebuf = null;
|
||||
eof = true;
|
||||
super.close();
|
||||
}
|
||||
|
||||
/** Sets the EOL characters to look for in the incoming stream. Setting
|
||||
* this to be null will cause it to look for any of <CR>, <LF>, or <CRLF>.
|
||||
* Note that null (the default) could cause up to one extra to be held in
|
||||
* the buffer (in the case where the last byte read from the underlying
|
||||
* stream was <CR>, and no following byte (or EOF) has yet been read.)
|
||||
*/
|
||||
public void setInputEOL(ByteBuf buf) {
|
||||
linebuf.setInputEOL(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* End of line characters <CR> & <LF> or any combination
|
||||
* will be replaced by this string if it is present. Setting
|
||||
* this to a zero length string will cause them to be stripped.
|
||||
* Setting this to null will cause the EOL characters to be passed
|
||||
* through unchanged (the default).
|
||||
* @param buf ByteBuf representing EOL replacement string
|
||||
*/
|
||||
public void setOutputEOL(ByteBuf buf) {
|
||||
linebuf.setOutputEOL(buf);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.EventListener;
|
||||
import java.util.Vector;
|
||||
import java.util.Enumeration;
|
||||
|
||||
|
||||
/**
|
||||
* ListenersList is a thread-safe, reentrant class which
|
||||
* contains a list of EventListeners and enforce some
|
||||
* policy on event dispatching. <p>
|
||||
|
||||
* This class guarantees that events delivering is correctly
|
||||
* accomplished even if listeners are removed from or added to the list during
|
||||
* event dispatching. Added listeners, though, will not receive the current event. <p>
|
||||
|
||||
* Event listeners are returned <b>LIFO</b>. <p>
|
||||
|
||||
* User of this class must enclose event dispatching between
|
||||
* startDelivering()/stopDelivering() calls and pass the state object
|
||||
* to the nextListener call. <p>
|
||||
* <pre>
|
||||
* ListenerListState state = eventListeners.startDelivering();
|
||||
*
|
||||
* SomeEventListener el = (SomeEventListener)eventListeners.nextListener(state);
|
||||
* while (null != el) {
|
||||
* el.someEvent();
|
||||
* el = (SomeEventListener)eventListeners.nextListener(state);
|
||||
* }
|
||||
*
|
||||
* eventListeners.stopDelivering(state);
|
||||
* </pre>
|
||||
*/
|
||||
public class ListenerList
|
||||
{
|
||||
private Vector fListeners; // list of listeners
|
||||
private Vector fEnumerators; // list of enumerators for this list of listeners
|
||||
|
||||
/**
|
||||
* Construct an array of listeners with the specifed size. <p>
|
||||
* The array size is doubled every time an element is added
|
||||
* to a full array.
|
||||
*
|
||||
* @param aSize the required size
|
||||
*/
|
||||
public ListenerList(int aSize)
|
||||
{
|
||||
fListeners = new Vector(aSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an array of listeners with the specifed size. <p>
|
||||
* The array size is doubled every time an element is added
|
||||
* to a full array.
|
||||
*
|
||||
*/
|
||||
public ListenerList()
|
||||
{
|
||||
fListeners = new Vector(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a new event listener for the class of events
|
||||
* this ListenersList is mantaining.
|
||||
*
|
||||
* @param aListener a listener for the specific set of events
|
||||
*/
|
||||
public void addListener(EventListener aListener)
|
||||
{
|
||||
fListeners.addElement(aListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a listener from the list of listeners this
|
||||
* ListenersList is mantaining.<p>
|
||||
* Existing and valid state object are updated to reflect
|
||||
* this change.
|
||||
*
|
||||
* @param aListener a listener for the specific set of events
|
||||
*/
|
||||
public void removeListener(EventListener aListener)
|
||||
{
|
||||
synchronized(fListeners) {
|
||||
// find and remove the element
|
||||
int index = fListeners.indexOf(aListener);
|
||||
if (index != -1) {
|
||||
try {
|
||||
fListeners.removeElementAt(index);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
Assert.Assertion(false); // no way!!
|
||||
}
|
||||
|
||||
// go through the list of live state objects and update the
|
||||
// index if necessary
|
||||
if (fEnumerators != null) {
|
||||
for (int i =0; i < fEnumerators.size(); i++) {
|
||||
ListenerListState state = (ListenerListState)fEnumerators.elementAt(i);
|
||||
if (index < state.fIndex) {
|
||||
state.fIndex--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A user of this class is starting event delivery. <p>
|
||||
* The state object represents the state of the list for
|
||||
* that user and has to be passed in every nextListener call.
|
||||
*
|
||||
* @param aListener a listener for the specific set of events
|
||||
* @return ListenerListState the state of the list for the caller
|
||||
*/
|
||||
public ListenerListState startDelivering()
|
||||
{
|
||||
synchronized(fListeners) {
|
||||
ListenerListState state = new ListenerListState(fListeners);
|
||||
if (null == fEnumerators) {
|
||||
fEnumerators = new Vector(1);
|
||||
}
|
||||
fEnumerators.addElement(state);
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A user completed or aborted event delivering. <p>
|
||||
*
|
||||
* @return aState the state of the list for the caller
|
||||
*/
|
||||
public void stopDelivering(ListenerListState aState)
|
||||
{
|
||||
synchronized(fListeners) {
|
||||
fEnumerators.removeElement(aState);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next EventListener in the array. <p>
|
||||
* Listeners are returned with a last-in/first-out (LIFO) policy.
|
||||
*
|
||||
* @return aState the state of the list for the caller
|
||||
*/
|
||||
public EventListener nextListener(ListenerListState aState)
|
||||
{
|
||||
synchronized(fListeners) {
|
||||
EventListener listener = null;
|
||||
|
||||
if (--aState.fIndex >= 0) {
|
||||
try {
|
||||
listener = (EventListener)fListeners.elementAt(aState.fIndex);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
Assert.Assertion(false);
|
||||
aState.fIndex = -1; // invalid state
|
||||
}
|
||||
}
|
||||
|
||||
return listener;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* ListenersListState keeps the index into the array of
|
||||
* listeners for the ListListeners class. <p>
|
||||
* Because a state is created every time event dispatching
|
||||
* occurs instances of this class act like local references
|
||||
* into the array and hence are thread-safe. <p>
|
||||
* This class does not expose any behavior and is entirely
|
||||
* for use by the ListenerList.
|
||||
*/
|
||||
public class ListenerListState
|
||||
{
|
||||
int fIndex;
|
||||
|
||||
ListenerListState(Vector aVector)
|
||||
{
|
||||
fIndex = aVector.size();
|
||||
}
|
||||
|
||||
ListenerListState()
|
||||
{
|
||||
fIndex = -1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
#!gmake
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License
|
||||
# Version 1.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.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS"
|
||||
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
# the License for the specific language governing rights and limitations
|
||||
# under the License.
|
||||
#
|
||||
# The Original Code is the Grendel mail/news client.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape Communications
|
||||
# Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
# Netscape Communications Corporation. All Rights Reserved.
|
||||
|
||||
SRCS= \
|
||||
Abacus.java \
|
||||
ArrayEnumeration.java \
|
||||
Assert.java \
|
||||
AssertionError.java \
|
||||
AssertionException.java \
|
||||
Atom.java \
|
||||
AtomHashtable.java \
|
||||
AttributeValuePair.java \
|
||||
ByteBuf.java \
|
||||
ByteLineBuffer.java \
|
||||
ByteToCharConverterEnumeration.java \
|
||||
CacheOutputStream.java \
|
||||
CharArray.java \
|
||||
CharArrayIterator.java \
|
||||
CharToByteConverterEnumeration.java \
|
||||
ClasspathEntryEnumeration.java \
|
||||
Comparer.java \
|
||||
ConfigUtils.java \
|
||||
Counter.java \
|
||||
DataExtension.java \
|
||||
DefaultPreferences.java \
|
||||
EnumerationEnumerator.java \
|
||||
HashtableBase.java \
|
||||
HashtableLite.java \
|
||||
HashtableRecycler.java \
|
||||
IDMap.java \
|
||||
LineBufferingInputStream.java \
|
||||
ListenerList.java \
|
||||
ListenerListState.java \
|
||||
MemoryManager.java \
|
||||
MemoryMonitor.java \
|
||||
MemoryPressure.java \
|
||||
NetworkDate.java \
|
||||
NullEnumeration.java \
|
||||
NullJavaEnumeration.java \
|
||||
Preferences.java \
|
||||
PreferencesBase.java \
|
||||
PreferencesFactory.java \
|
||||
PrefetchEnumeration.java \
|
||||
QSort.java \
|
||||
RWLock.java \
|
||||
RandomAccessFileWithByteLines.java \
|
||||
Recycler.java \
|
||||
SelfTest.java \
|
||||
SelfTestAtom.java \
|
||||
SelfTestException.java \
|
||||
SelfTestIDMap.java \
|
||||
SelfTestRWLock.java \
|
||||
SignedInteger.java \
|
||||
SingleEnumeration.java \
|
||||
StringBuf.java \
|
||||
StringBufRecycler.java \
|
||||
StringUtils.java \
|
||||
TempFile.java \
|
||||
TimeBomb.java \
|
||||
URLClassLoader.java \
|
||||
Vec.java \
|
||||
VectorRecycler.java \
|
||||
WeakLink.java \
|
||||
WeakLinkArray.java \
|
||||
WeakLinkArrayEnumeration.java \
|
||||
$(NULL)
|
||||
|
||||
include ../../rules.mk
|
|
@ -0,0 +1,39 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
public class MemoryManager {
|
||||
static WeakLinkArray gHandlers;
|
||||
|
||||
static synchronized public void Add(MemoryPressure aHandler) {
|
||||
if (gHandlers == null) {
|
||||
gHandlers = new WeakLinkArray();
|
||||
}
|
||||
gHandlers.addElement(aHandler);
|
||||
}
|
||||
|
||||
static synchronized public void Remove(MemoryPressure aHandler) {
|
||||
if (gHandlers != null) {
|
||||
gHandlers.removeElement(aHandler);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.lang.Runtime;
|
||||
|
||||
/**
|
||||
* A utility class to help track memory usage during development.
|
||||
* The interface is simple. Just create the monitor, do your business,
|
||||
* and then invoke the done method. <p>
|
||||
*
|
||||
* The figure for the ammount of memory allocated should be accurate
|
||||
* but the number for the ammount of garbage can be off by quite a bit
|
||||
* if any garbage collection was done between the monitor's creation
|
||||
* and the call to done. <p>
|
||||
*
|
||||
* Currently, it just prints some stuff to the console. I'd like to
|
||||
* extend it so it creates a window and displays it's info in that.
|
||||
*
|
||||
* @author Thom FillABomb :-)
|
||||
*/
|
||||
public class MemoryMonitor
|
||||
{
|
||||
Runtime fSystem;
|
||||
|
||||
long fFreeAtStart,
|
||||
fFreeAtEnd,
|
||||
fGarbageGenerated;
|
||||
|
||||
String fUserString = null;
|
||||
|
||||
public MemoryMonitor (String monitorDescription)
|
||||
{
|
||||
fUserString = monitorDescription;
|
||||
initialize();
|
||||
}
|
||||
|
||||
public MemoryMonitor ()
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
protected void initialize ()
|
||||
{
|
||||
fSystem = Runtime.getRuntime();
|
||||
beginMonitor();
|
||||
}
|
||||
|
||||
public void done ()
|
||||
{
|
||||
finishMonitor ();
|
||||
|
||||
System.out.println();
|
||||
|
||||
if (fUserString != null)
|
||||
System.out.println (fUserString);
|
||||
|
||||
System.out.println (" Starting Free: " + fFreeAtStart);
|
||||
System.out.println (" Ending Free: " + fFreeAtEnd);
|
||||
System.out.println (" Memory Delta: " + (fFreeAtStart - fFreeAtEnd));
|
||||
System.out.println ("Garbage Generated: " + fGarbageGenerated);
|
||||
}
|
||||
|
||||
protected void freeUpMemory ()
|
||||
{
|
||||
// we might want to tickle Kipp's memory Manager here as well...
|
||||
|
||||
fSystem.runFinalization();
|
||||
// might want to sleep here
|
||||
fSystem.gc();
|
||||
fSystem.gc();
|
||||
}
|
||||
|
||||
void beginMonitor ()
|
||||
{
|
||||
freeUpMemory();
|
||||
fFreeAtStart = fSystem.freeMemory();
|
||||
}
|
||||
|
||||
void finishMonitor ()
|
||||
{
|
||||
long totalUsed, minusGarbage;
|
||||
|
||||
totalUsed = fSystem.freeMemory();
|
||||
freeUpMemory();
|
||||
minusGarbage = fSystem.freeMemory();
|
||||
|
||||
// it would also be interesting to purge the recyclers here and
|
||||
// see how much memory they're occupying
|
||||
|
||||
fGarbageGenerated = minusGarbage - totalUsed;
|
||||
fFreeAtEnd = minusGarbage;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
public interface MemoryPressure {
|
||||
/**
|
||||
* This method is called by the garbage collector just before a
|
||||
* garbage collection is about to begin.
|
||||
*/
|
||||
void preGC(long aCurrentHeapSpace, long aMaximumHeapSpace);
|
||||
|
||||
/**
|
||||
* This method is called by the garbage collector just after a
|
||||
* collection has finished.
|
||||
*/
|
||||
void postGC(long aCurrentHeapSpace, long aMaximumHeapSpace);
|
||||
|
||||
/**
|
||||
* This method is called by the garbage collector when the
|
||||
* heap is essentially full and can no longer grow. When this
|
||||
* occurs <B>all</B> caches of objects should be flushed.
|
||||
*/
|
||||
void panic();
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,43 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This just returns an enumeration which never has anything in it.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class NullEnumeration implements Enumeration {
|
||||
|
||||
public static final Enumeration kInstance = new NullEnumeration ();
|
||||
|
||||
protected NullEnumeration ()
|
||||
{
|
||||
}
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
return false;
|
||||
}
|
||||
public Object nextElement() throws NoSuchElementException {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This just returns an enumeration which never has anything in it.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class NullJavaEnumeration implements Enumeration {
|
||||
|
||||
public static final Enumeration kInstance = new NullJavaEnumeration ();
|
||||
|
||||
protected NullJavaEnumeration ()
|
||||
{
|
||||
}
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
return false;
|
||||
}
|
||||
public Object nextElement() throws NoSuchElementException {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Properties;
|
||||
|
||||
/** This is an interface to get things from the Preferences database.
|
||||
@see PreferencesFactory */
|
||||
|
||||
public interface Preferences {
|
||||
/** Add a table of default values. You must add defaults for each
|
||||
preference you use. */
|
||||
void addDefaults(Properties defs);
|
||||
|
||||
/** Given a name of a preference, return its value as a String. If it's not
|
||||
defined, return the given default. */
|
||||
String getString(String prefname, String defaultValue);
|
||||
|
||||
/** Given a name of a preference, return its value as a String. */
|
||||
String getString(String prefname);
|
||||
|
||||
/** Given a name of a preference, return its value as an int. If it's not
|
||||
defined, return the given default. */
|
||||
int getInt(String prefname, int defaultValue);
|
||||
|
||||
/** Given a name of a preference, return its value as an int. */
|
||||
int getInt(String prefname);
|
||||
|
||||
/** Given a name of a preference, return its value as a boolean. If it's not
|
||||
defined, return the given default. */
|
||||
boolean getBoolean(String prefname, boolean defaultValue);
|
||||
|
||||
/** Given a name of a preference, return its value as a boolean. */
|
||||
boolean getBoolean(String prefname);
|
||||
|
||||
/** Given a name of a preference, return its value as an File. If it's not
|
||||
defined, return the given default. */
|
||||
File getFile(String prefname, File defaultValue);
|
||||
|
||||
/** Assign a String value to the given preference. */
|
||||
void putString(String prefname, String value);
|
||||
|
||||
/** Assign an int value to the given preference. */
|
||||
void putInt(String prefname, int value);
|
||||
|
||||
/** Assign a boolean value to the given preference. */
|
||||
void putBoolean(String prefname, boolean value);
|
||||
|
||||
/** Return the preferences as a Properties object */
|
||||
Properties getAsProperties();
|
||||
};
|
|
@ -0,0 +1,170 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
class PreferencesBase extends Properties implements Preferences {
|
||||
|
||||
static final String gPrefsPath = System.getProperties().getProperty("user.home");
|
||||
static final String gPrefsFile = "xena.pref";
|
||||
|
||||
PreferencesBase() {
|
||||
super();
|
||||
|
||||
File infile = new File(new File(gPrefsPath), gPrefsFile);
|
||||
InputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(infile);
|
||||
load(in);
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
void writePrefs() {
|
||||
File outfile = new File(new File(gPrefsPath), gPrefsFile);
|
||||
OutputStream out = null;
|
||||
try {
|
||||
out = new FileOutputStream(outfile);
|
||||
save(out, "Xena User Preferences. Do not directly modify this file!");
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void addDefaults(Properties defs) {
|
||||
if(defs == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(defaults == null) {
|
||||
defaults = defs;
|
||||
return;
|
||||
}
|
||||
|
||||
for(Enumeration e = defs.keys(); e.hasMoreElements();) {
|
||||
Object key = e.nextElement();
|
||||
defaults.put(key, defs.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
public String getString(String name, String defaultValue) {
|
||||
return getProperty(name, defaultValue);
|
||||
}
|
||||
|
||||
public String getString(String name)
|
||||
throws MissingResourceException {
|
||||
String result = getProperty(name);
|
||||
if(result == null) {
|
||||
throw new MissingResourceException(name + " is missing!", "", name);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getInt(String name, int defaultValue) {
|
||||
String str = getString(name, null);
|
||||
int result = defaultValue;
|
||||
if (str != null) {
|
||||
try {
|
||||
result = Integer.parseInt(str);
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getInt(String name)
|
||||
throws MissingResourceException, NumberFormatException {
|
||||
String str;
|
||||
try {
|
||||
str = getString(name);
|
||||
} catch(MissingResourceException e) {
|
||||
throw e;
|
||||
}
|
||||
int result;
|
||||
try {
|
||||
result = Integer.parseInt(str);
|
||||
} catch (NumberFormatException e) {
|
||||
throw e;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean getBoolean(String name, boolean defaultValue) {
|
||||
String str = getString(name, null);
|
||||
boolean result = defaultValue;
|
||||
if (str != null) {
|
||||
result = Boolean.valueOf(str).booleanValue();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean getBoolean(String name)
|
||||
throws MissingResourceException {
|
||||
String str;
|
||||
try {
|
||||
str = getString(name);
|
||||
} catch(MissingResourceException e) {
|
||||
throw e;
|
||||
}
|
||||
return Boolean.valueOf(str).booleanValue();
|
||||
}
|
||||
|
||||
public File getFile(String name, File defaultValue) {
|
||||
String str = getString(name, null);
|
||||
File result = defaultValue;
|
||||
if (str != null) {
|
||||
result = new File(str);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Assign a String value to the given preference. */
|
||||
public void putString(String prefName, String value) {
|
||||
put(prefName, value);
|
||||
writePrefs();
|
||||
}
|
||||
|
||||
/** Assign an int value to the given preference. */
|
||||
public void putInt(String prefName, int value) {
|
||||
put(prefName, (String)(""+value));
|
||||
writePrefs();
|
||||
}
|
||||
|
||||
/** Assign a boolean value to the given preference. */
|
||||
public void putBoolean(String prefName, boolean value) {
|
||||
put(prefName, (String)(""+value));
|
||||
writePrefs();
|
||||
}
|
||||
|
||||
/** Return the preferences as a Properties object */
|
||||
public Properties getAsProperties() {
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
/** A factory to return the (singleton) preferences object. */
|
||||
|
||||
public class PreferencesFactory {
|
||||
static Preferences fPrefs = null;
|
||||
|
||||
/** Return the preferences object. */
|
||||
public static Preferences Get() {
|
||||
if (fPrefs == null) {
|
||||
synchronized(PreferencesFactory.class) {
|
||||
// Make sure some other thread didn't already make it.
|
||||
if (fPrefs == null) {
|
||||
fPrefs = new PreferencesBase();
|
||||
}
|
||||
}
|
||||
}
|
||||
return fPrefs;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*
|
||||
* Created: Frank Tang <ftang@netscape.com>
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
public abstract class PrefetchEnumeration implements Enumeration {
|
||||
protected boolean initialized = false;
|
||||
protected Object fFetch = null;
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
private void init()
|
||||
{
|
||||
if(! initialized )
|
||||
{
|
||||
fFetch = fetch();
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
public Object nextElement()
|
||||
{
|
||||
if(! initialized)
|
||||
init();
|
||||
Object current = fFetch;
|
||||
fFetch = fetch();
|
||||
return current;
|
||||
}
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
public boolean hasMoreElements()
|
||||
{
|
||||
if(! initialized)
|
||||
init();
|
||||
return (fFetch != null);
|
||||
}
|
||||
/*
|
||||
*
|
||||
* @author ftang
|
||||
* @version $Revision: 1.1 $
|
||||
* @see
|
||||
*
|
||||
*/
|
||||
abstract protected Object fetch();
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
/** Implements QuickSort, on an array of objects.
|
||||
An implementor of `Comparer' is passed in to compare two objects.
|
||||
*/
|
||||
public class QSort {
|
||||
|
||||
private Comparer comp;
|
||||
|
||||
/** Create a QSort object.
|
||||
One way to use this would with dynamic class creation:
|
||||
<PRE>
|
||||
QSort sorter = new QSort(new Comparer() {
|
||||
public int compare(Object a, Object b) {
|
||||
if (a.key == b.key) return 0;
|
||||
else if (a.key < b.key) return -1;
|
||||
else return 1;
|
||||
}
|
||||
});
|
||||
sorter.sort(array);
|
||||
</PRE>
|
||||
*/
|
||||
public QSort(Comparer c) {
|
||||
comp = c;
|
||||
}
|
||||
|
||||
/** Sorts the array, according to the Comparer. */
|
||||
public void sort(Object[] list) {
|
||||
quicksort(list, 0, list.length - 1);
|
||||
}
|
||||
|
||||
/** Sorts a subsequence of the array, according to the Comparer. */
|
||||
public void sort(Object[] list, int start, int end) {
|
||||
quicksort(list, start, end - 1);
|
||||
}
|
||||
|
||||
private void quicksort(Object[] list, int p, int r) {
|
||||
if (p < r) {
|
||||
int q = partition(list,p,r);
|
||||
if (q == r) {
|
||||
q--;
|
||||
}
|
||||
quicksort(list,p,q);
|
||||
quicksort(list,q+1,r);
|
||||
}
|
||||
}
|
||||
|
||||
private int partition (Object[] list, int p, int r) {
|
||||
Object pivot = list[p];
|
||||
int lo = p;
|
||||
int hi = r;
|
||||
|
||||
while (true) {
|
||||
|
||||
while (comp.compare(list[hi], pivot) >= 0 &&
|
||||
lo < hi) {
|
||||
hi--;
|
||||
}
|
||||
while (comp.compare(list[lo], pivot) < 0 &&
|
||||
lo < hi) {
|
||||
lo++;
|
||||
}
|
||||
if (lo < hi) {
|
||||
Object T = list[lo];
|
||||
list[lo] = list[hi];
|
||||
list[hi] = T;
|
||||
}
|
||||
else return hi;
|
||||
}
|
||||
}
|
||||
|
||||
// public static void main(String argv[]) {
|
||||
// String array[] = { "7", "3", "0", "4", "5", "6", "2", "1" };
|
||||
// QSort sorter = new QSort(new Comparer() {
|
||||
// public int compare(Object a, Object b) {
|
||||
// int ai = Integer.parseInt((String) a);
|
||||
// int bi = Integer.parseInt((String) b);
|
||||
// if (ai == bi) return 0;
|
||||
// else if (ai < bi) return -1;
|
||||
// else return 1;
|
||||
// }
|
||||
// });
|
||||
// sorter.sort(array);
|
||||
// for (int i = 0; i < array.length; i++)
|
||||
// System.out.print(array[i] + " ");
|
||||
// System.out.println();
|
||||
// }
|
||||
|
||||
}
|
|
@ -0,0 +1,312 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
/**
|
||||
* A "read-write" lock. This lock allows for an arbitrary number of
|
||||
* simultaneous readers. The lock can be upgraded to a write lock in two
|
||||
* ways. First, the lock can be upgraded without guaranteeing invariance
|
||||
* across the transition (in other words, the read lock may need to be
|
||||
* released before the write lock can be acquired). The other form of
|
||||
* upgrade guarantees invariance; however, the upgrade can only be
|
||||
* performed by initially locking the lock using the invariant read lock
|
||||
* enter method. Upgrading the lock in either case involves waiting until
|
||||
* there are no more readers. This implementation gives priority to
|
||||
* upgrades and invariant locks which may lead to reader starvation. <p>
|
||||
*
|
||||
* Each thread using the lock may re-enter the lock as many times as
|
||||
* needed. However, attempting to re-enter the lock with the invariant
|
||||
* read lock will fail unless the lock was originally entered that way by
|
||||
* the invoking thread. <p>
|
||||
*
|
||||
* Only one thread may enter the invariant read lock at a time; other
|
||||
* threads attempting this will block until the owning thread exits the
|
||||
* lock completely. <p>
|
||||
*
|
||||
* Note that the implementation assumes that the user of instances of
|
||||
* this class properly pairs the enters/exits. <p>
|
||||
*/
|
||||
public final class RWLock {
|
||||
private int fNumReaders;
|
||||
private Thread fWriteLockOwner;
|
||||
private int fWriteLockCount;
|
||||
private Thread fInvariantLockOwner;
|
||||
private int fInvariantLockCount;
|
||||
|
||||
public RWLock() {
|
||||
fStateList = new LockState();
|
||||
fStateList.fNext = fStateList;
|
||||
fStateList.fPrev = fStateList;
|
||||
fFreeList = new LockState();
|
||||
fFreeList.fNext = fFreeList;
|
||||
fFreeList.fPrev = fFreeList;
|
||||
}
|
||||
|
||||
public synchronized void enterReadLock()
|
||||
throws InterruptedException
|
||||
{
|
||||
Thread me = Thread.currentThread();
|
||||
|
||||
// Wait for writer, if any, to release the lock
|
||||
if ((fWriteLockOwner != null) && (me != fWriteLockOwner)) {
|
||||
while (fWriteLockOwner != null) {
|
||||
wait();
|
||||
}
|
||||
}
|
||||
|
||||
// XXX write me:
|
||||
// If my lock count is zero and there is a writer waiting, block
|
||||
// until the writer is done
|
||||
|
||||
// Add another state record to the list
|
||||
appendLockState(me, kRead);
|
||||
fNumReaders++;
|
||||
}
|
||||
|
||||
public synchronized void exitReadLock() {
|
||||
Thread me = Thread.currentThread();
|
||||
removeLockState(me, kRead);
|
||||
fNumReaders--;
|
||||
notify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter the invariant read lock. Only one thread at a time can hold
|
||||
* the invariant read lock. This lock guarantees to upgrade to a write
|
||||
* lock without needing to release the read lock.
|
||||
*/
|
||||
public synchronized void enterInvariantReadLock()
|
||||
throws InterruptedException
|
||||
{
|
||||
Thread me = Thread.currentThread();
|
||||
if (me != fInvariantLockOwner) {
|
||||
// If we don't have the invariant read lock already then we cannot
|
||||
// try to get it if we are holding either a read or a write lock
|
||||
if (isLocked(me, kRead) || isLocked(me, kWrite)) {
|
||||
throw new Error("enterInvariantReadLock while holding r/w lock");
|
||||
}
|
||||
|
||||
/**
|
||||
* If we get here it means we don't currently hold the invariant read
|
||||
* lock and we aren't holding any read locks or write locks which
|
||||
* means we can't be the fWriteLockOwner or the fInvariantOwner.
|
||||
* Wait until either of those threads, if any, is done with the lock.
|
||||
*/
|
||||
while ((fWriteLockOwner != null) || (fInvariantLockOwner != null)) {
|
||||
wait();
|
||||
}
|
||||
|
||||
// Claim the lock
|
||||
fInvariantLockOwner = me;
|
||||
}
|
||||
fInvariantLockCount++;
|
||||
fNumReaders++;
|
||||
appendLockState(me, kInvariantRead);
|
||||
}
|
||||
|
||||
public synchronized void exitInvariantReadLock() {
|
||||
Thread me = Thread.currentThread();
|
||||
removeLockState(me, kInvariantRead);
|
||||
--fNumReaders;
|
||||
if (--fInvariantLockCount == 0) {
|
||||
fInvariantLockOwner = null;
|
||||
}
|
||||
notify();
|
||||
}
|
||||
|
||||
public synchronized void enterWriteLock()
|
||||
throws InterruptedException
|
||||
{
|
||||
Thread me = Thread.currentThread();
|
||||
if (me != fWriteLockOwner) {
|
||||
// Count up how many read-locks we have currently. The only possible
|
||||
// type of lock state is kRead or kInvariantRead.
|
||||
int readCount = 0;
|
||||
LockState list = fStateList.fPrev;
|
||||
while (list != fStateList) {
|
||||
LockState prev = list.fPrev;
|
||||
if (list.fThread == me) {
|
||||
Assert.Assertion(list.fState != kWrite);
|
||||
readCount++;
|
||||
}
|
||||
list = prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we have the invariant read lock then we don't have to release
|
||||
* our read locks, otherwise we do. When we do we must notify any
|
||||
* other threads that are waiting for this to occur. When we don't
|
||||
* we change the wait loop below to wait until all the <b>other</b>
|
||||
* read locks are released isntead of waiting until <b>all</b> the
|
||||
* read locks are released.
|
||||
*/
|
||||
int baseNumReaders = readCount;
|
||||
if (me != fInvariantLockOwner) {
|
||||
// Release our read locks now
|
||||
baseNumReaders = 0;
|
||||
fNumReaders -= readCount;
|
||||
notify();
|
||||
}
|
||||
|
||||
// Wait for all other readers or a writer to exit the lock
|
||||
while ((fWriteLockOwner != null) || (fNumReaders > baseNumReaders)) {
|
||||
wait();
|
||||
}
|
||||
|
||||
// At this point fWriteLockOwner == null and fNumReaders ==
|
||||
// baseNumReaders which means that we can claim the
|
||||
// write-lock. Restore fNumReaders to account for any of our read
|
||||
// locks on the list.
|
||||
if (me != fInvariantLockOwner) {
|
||||
// Recover our read locks. Note that we left them on the state
|
||||
// list this entire time, we just reduced the counts to that
|
||||
// the various wait loops would think they were gone.
|
||||
fNumReaders += readCount;
|
||||
}
|
||||
fWriteLockOwner = me;
|
||||
}
|
||||
fWriteLockCount++;
|
||||
appendLockState(me, kWrite);
|
||||
}
|
||||
|
||||
public synchronized void exitWriteLock() {
|
||||
Thread me = Thread.currentThread();
|
||||
removeLockState(me, kWrite);
|
||||
if (--fWriteLockCount == 0) {
|
||||
fWriteLockOwner = null;
|
||||
}
|
||||
notify();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
static class LockState {
|
||||
// Linkage for either fStateStack or for fFreeList
|
||||
LockState fPrev, fNext;
|
||||
Thread fThread;
|
||||
int fState;
|
||||
}
|
||||
|
||||
// Legal state values for a LockState. These indicate what kind
|
||||
// of enter was done on the lock.
|
||||
static final int kRead = 0;
|
||||
static final int kWrite = 1;
|
||||
static final int kInvariantRead = 2;
|
||||
static String[] kStateToString = {
|
||||
"read-lock", "write-lock", "invariant-read-lock"
|
||||
};
|
||||
|
||||
/**
|
||||
* Circular list of LockState objects. When the lock changes state (via
|
||||
* one of the three enter methods) we append a LockState object to the
|
||||
* end of the stack. When a thread exits the lock we find it's last
|
||||
* LockState object and remove it from the list.
|
||||
*/
|
||||
private LockState fStateList;
|
||||
|
||||
/**
|
||||
* A list of free LockState objects used to reduce the execution
|
||||
* time for allocation.
|
||||
*/
|
||||
private LockState fFreeList;
|
||||
private int fFreeListLength;
|
||||
private static final int kMaxFreeListLength = 10;
|
||||
|
||||
/**
|
||||
* See if aThread has the given type of lock
|
||||
*/
|
||||
private boolean isLocked(Thread aThread, int aHow) {
|
||||
LockState list = fStateList.fPrev;
|
||||
while (list != fStateList) {
|
||||
if (list.fThread == aThread) {
|
||||
if (list.fState == aHow) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
list = list.fPrev;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void appendLockState(Thread aThread, int aState) {
|
||||
LockState ls = newLockState();
|
||||
ls.fThread = aThread;
|
||||
ls.fState = aState;
|
||||
|
||||
// Append ls to the state list
|
||||
LockState list = fStateList;
|
||||
ls.fNext = list;
|
||||
ls.fPrev = list.fPrev;
|
||||
list.fPrev.fNext = ls;
|
||||
list.fPrev = ls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk up the thread state list and look for aThread. Verify that the
|
||||
* LockState is in the right state and if it is then we remove that
|
||||
* LockState from the list.
|
||||
*/
|
||||
private void removeLockState(Thread aThread, int aState) {
|
||||
LockState tos = fStateList.fPrev;
|
||||
while (tos != fStateList) {
|
||||
if (tos.fThread == aThread) {
|
||||
if (tos.fState != aState) {
|
||||
throw new Error("mismatched lock exit: entry=" +
|
||||
kStateToString[tos.fState] + " exit=" +
|
||||
kStateToString[aState]);
|
||||
}
|
||||
|
||||
// Remove tos from the list
|
||||
tos.fPrev.fNext = tos.fNext;
|
||||
tos.fNext.fPrev = tos.fPrev;
|
||||
freeLockState(tos);
|
||||
return;
|
||||
}
|
||||
tos = tos.fPrev;
|
||||
}
|
||||
throw new Error("unmatched lock exit");
|
||||
}
|
||||
|
||||
private LockState newLockState() {
|
||||
if (fFreeListLength == 0) {
|
||||
return new LockState();
|
||||
}
|
||||
|
||||
// Get a LockState from the free list
|
||||
LockState tos = fFreeList.fPrev;
|
||||
tos.fPrev.fNext = tos.fNext;
|
||||
tos.fNext.fPrev = tos.fPrev;
|
||||
fFreeListLength--;
|
||||
return tos;
|
||||
}
|
||||
|
||||
private void freeLockState(LockState aState) {
|
||||
if (fFreeListLength < kMaxFreeListLength) {
|
||||
LockState list = fFreeList;
|
||||
|
||||
// Append aState to the free list
|
||||
aState.fNext = list;
|
||||
aState.fPrev = list.fPrev;
|
||||
list.fPrev.fNext = aState;
|
||||
list.fPrev = aState;
|
||||
fFreeListLength++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/* RandomAccessFileWithByteLines takes a RandomAccessFile, and provides a way
|
||||
* to get data a line at a time from it. The API probably needs rethinking.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import calypso.util.Assert;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class RandomAccessFileWithByteLines {
|
||||
static final int INITBUFSIZE = 128;
|
||||
|
||||
protected RandomAccessFile fInput;
|
||||
protected byte[] fBuffer = new byte[INITBUFSIZE];
|
||||
protected int fOffset;
|
||||
protected int fEnd;
|
||||
|
||||
|
||||
public RandomAccessFileWithByteLines(RandomAccessFile f) {
|
||||
fInput = f;
|
||||
}
|
||||
|
||||
public boolean readLine(ByteBuf buf) throws IOException {
|
||||
buf.setLength(0);
|
||||
do {
|
||||
for (int i=fOffset ; i<fEnd ; i++) {
|
||||
if (fBuffer[i] == '\r' || fBuffer[i] == '\n') {
|
||||
buf.append(fBuffer, fOffset, i - fOffset);
|
||||
fOffset = i;
|
||||
eatNewline();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
buf.append(fBuffer, fOffset, fEnd - fOffset);
|
||||
fOffset = fEnd;
|
||||
} while (fill());
|
||||
return (buf.length() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Eat up one newline if present in the fBuffer. If a newline
|
||||
* was eaten up return true otherwise false. This will handle
|
||||
* mac (\r), unix (\n) and windows (\r\n) style of newlines
|
||||
* transparently.
|
||||
*/
|
||||
public boolean eatNewline() throws IOException {
|
||||
boolean eaten = false;
|
||||
int amount = fEnd - fOffset;
|
||||
if (amount < 2) {
|
||||
if (!fillForCapacity(2)) {
|
||||
// Couldn't get two characters
|
||||
if (fEnd - fOffset == 0) {
|
||||
return false;
|
||||
}
|
||||
if ((fBuffer[fOffset] == '\r') || (fBuffer[fOffset] == '\n')) {
|
||||
fOffset++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (fBuffer[fOffset] == '\r') {
|
||||
fOffset++;
|
||||
eaten = true;
|
||||
}
|
||||
if (fBuffer[fOffset] == '\n') {
|
||||
eaten = true;
|
||||
fOffset++;
|
||||
}
|
||||
return eaten;
|
||||
}
|
||||
|
||||
|
||||
public long getFilePointer() throws IOException {
|
||||
return fInput.getFilePointer() - (fEnd - fOffset);
|
||||
}
|
||||
|
||||
public void seek(long loc) throws IOException {
|
||||
fInput.seek(loc);
|
||||
fOffset = 0;
|
||||
fEnd = 0;
|
||||
}
|
||||
|
||||
protected boolean fill() throws IOException {
|
||||
if (fEnd - fOffset != 0) {
|
||||
throw new IOException("fill of non-empty fBuffer");
|
||||
}
|
||||
fOffset = 0;
|
||||
fEnd = fInput.read(fBuffer);
|
||||
if (fEnd < 0) {
|
||||
fEnd = 0;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the fBuffer, keeping whatever is unread in the fBuffer and
|
||||
* ensuring that "capacity" characters of total filled fBuffer
|
||||
* space is available. Return false if the final amount of data
|
||||
* in the fBuffer is less than capacity, otherwise return true.
|
||||
*/
|
||||
protected boolean fillForCapacity(int capacity) throws IOException {
|
||||
int remainingData = fEnd - fOffset;
|
||||
if (remainingData >= capacity) {
|
||||
// The fBuffer already holds enough data to satisfy capacity
|
||||
return true;
|
||||
}
|
||||
|
||||
// The fBuffer needs more data. See if the fBuffer itself must be
|
||||
// enlarged to statisfy capacity.
|
||||
if (capacity >= fBuffer.length) {
|
||||
// Grow the fBuffer to hold enough space
|
||||
int newBufLen = fBuffer.length * 2;
|
||||
if (newBufLen < capacity) newBufLen = capacity;
|
||||
byte newbuf[] = new byte[newBufLen];
|
||||
System.arraycopy(fBuffer, fOffset, newbuf, 0, remainingData);
|
||||
fOffset = 0;
|
||||
fEnd = remainingData;
|
||||
fBuffer = newbuf;
|
||||
} else {
|
||||
if (remainingData != 0) {
|
||||
// Slide the data that is currently present in the fBuffer down
|
||||
// to the start of the fBuffer
|
||||
System.arraycopy(fBuffer, fOffset, fBuffer, 0, remainingData);
|
||||
fOffset = 0;
|
||||
fEnd = remainingData;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill up the remainder of the fBuffer
|
||||
int mustRead = capacity - remainingData;
|
||||
int nb = fInput.read(fBuffer, remainingData,
|
||||
fBuffer.length-remainingData);
|
||||
if (nb < 0) {
|
||||
return false;
|
||||
}
|
||||
fEnd += nb;
|
||||
if (nb < mustRead) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void readFully(byte[] arr, int off, int length) throws IOException {
|
||||
Assert.Assertion(fOffset == fEnd);
|
||||
fInput.readFully(arr, off, length);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author gess 04-16-97 1:44pm
|
||||
* @version $Revision: 1.1 $
|
||||
* @notes This is a general purpose recycler.
|
||||
* It contains objects of a specified capacity.
|
||||
* If you ask for a recycled object and we have
|
||||
* one, then it's returned as object as you must typecast.
|
||||
* If we don't have a recycled object, we return null.
|
||||
*/
|
||||
|
||||
public class Recycler implements MemoryPressure
|
||||
{
|
||||
Object[] fBuffer;
|
||||
int fCount;
|
||||
int fCapacity;
|
||||
final static int gDefaultCapacity = 100;
|
||||
|
||||
/******************************************
|
||||
* @author gess 04-16-97 1:40pm
|
||||
* @param
|
||||
* @return
|
||||
* @notes default constructor, assumes
|
||||
buffer capacity of 100
|
||||
*******************************************/
|
||||
public Recycler()
|
||||
{
|
||||
MemoryManager.Add(this);
|
||||
fCapacity=gDefaultCapacity;
|
||||
reset();
|
||||
}
|
||||
|
||||
/********************************************************
|
||||
* @author gess 04-16-97 1:40pm
|
||||
* @param aGivenCapacity -- size of underlying buffer
|
||||
* @return
|
||||
* @notes constructor with capacity argument
|
||||
********************************************************/
|
||||
public Recycler(int aGivenCapacity)
|
||||
{
|
||||
MemoryManager.Add(this);
|
||||
fCapacity=aGivenCapacity;
|
||||
reset();
|
||||
}
|
||||
|
||||
/********************************************************
|
||||
* @author gess 04-16-97 1:43pm
|
||||
* @param none
|
||||
* @return none
|
||||
* @notes discards original buffer (if present) and creates
|
||||
a new buffer of size fCapacity
|
||||
*********************************************************/
|
||||
public void reset()
|
||||
{
|
||||
fBuffer= new Object[fCapacity];
|
||||
fCount = 0;
|
||||
}
|
||||
|
||||
/********************************************************
|
||||
* @author gess 04-16-97 1:43pm
|
||||
* @param anObject -- object to be recycled
|
||||
* @return none
|
||||
* @notes always drop on end of list; when capacity is
|
||||
reached, replaced last entry
|
||||
*********************************************************/
|
||||
public void recycle(Object anObject)
|
||||
{
|
||||
if (null!=anObject)
|
||||
{
|
||||
if (null==fBuffer)
|
||||
{
|
||||
reset();
|
||||
fBuffer[fCount++] = anObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fCount==fCapacity)
|
||||
{
|
||||
// Replace last entry with the new one,
|
||||
// to improve memory locality
|
||||
fBuffer[fCount-1] = anObject;
|
||||
}
|
||||
else
|
||||
fBuffer[fCount++] = anObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recycles the entire contents of the given list.
|
||||
*
|
||||
* @param
|
||||
* @return
|
||||
* @exception
|
||||
* @author gess 04-16-97 4:22pm
|
||||
**/
|
||||
public void recycle(Object anObjectArray[])
|
||||
{
|
||||
int count = anObjectArray.length;
|
||||
int index;
|
||||
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
recycle (anObjectArray[index]);
|
||||
anObjectArray[index] = null;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************
|
||||
* @author gess 04-16-97 1:43pm
|
||||
* @param none
|
||||
* @return object or null
|
||||
* @notes if we don't have any recycled objects, we
|
||||
return null. Objects we DO return must be
|
||||
type cast by you to the appropriate type.
|
||||
*********************************************************/
|
||||
public Object getRecycledObject()
|
||||
{
|
||||
Object result=null;
|
||||
if (fCount>0)
|
||||
{
|
||||
result=fBuffer[--fCount];
|
||||
fBuffer[fCount]=null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* @author gess 04-16-97 1:40pm
|
||||
* @param none
|
||||
* @return none
|
||||
* @notes causes buffer to be released and
|
||||
count to be reset to 0.
|
||||
*******************************************/
|
||||
public void empty()
|
||||
{
|
||||
fCount = 0;
|
||||
fBuffer = null;
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* @author gess 04-16-97 1:40pm
|
||||
* @param
|
||||
* @return
|
||||
* @notes copied from kipps implementation
|
||||
*******************************************/
|
||||
public void preGC(long aCurrentHeapSpace, long aMaximumHeapSpace)
|
||||
{
|
||||
// Discard our array of buffers so that the GC can
|
||||
// compact the heap nicely.
|
||||
empty();
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* @author gess 04-16-97 1:41pm
|
||||
* @param
|
||||
* @return
|
||||
* @notes copied from kipps implementation
|
||||
*******************************************/
|
||||
public void postGC(long aCurrentHeapSpace, long aMaximumHeapSpace)
|
||||
{
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* @author gess 04-16-97 1:40pm
|
||||
* @param
|
||||
* @return
|
||||
* @notes
|
||||
*******************************************/
|
||||
public void panic()
|
||||
{
|
||||
// Get rid of everything, including ourselves
|
||||
empty();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
/* ####
|
||||
import calypso.core.SystemLog;
|
||||
*/
|
||||
|
||||
/**
|
||||
* SelfTest for calypso.util package
|
||||
*
|
||||
* @author sclark 04-22-97 3:52pm
|
||||
* @notes runAllTests must be successfully run after every check-in
|
||||
*/
|
||||
public class SelfTest {
|
||||
public static void main(String args[]) {
|
||||
SelfTest selfTest = new SelfTest();
|
||||
try {
|
||||
selfTest.runAllTests();
|
||||
} catch (SelfTestException e) {
|
||||
System.err.println("SelfTestException: " + e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @author sclark 04-22-97 3:53pm
|
||||
**/
|
||||
public SelfTest()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
private void reset()
|
||||
{
|
||||
}
|
||||
|
||||
public void runAllTests()
|
||||
throws SelfTestException
|
||||
{
|
||||
runUnitTest();
|
||||
runThreadTest();
|
||||
runStressTest();
|
||||
runIDMapTest();
|
||||
runAtomTest();
|
||||
}
|
||||
|
||||
public void runUnitTest()
|
||||
throws SelfTestException
|
||||
{
|
||||
|
||||
/* ####
|
||||
SystemLog.Instance().log("============================");
|
||||
SystemLog.Instance().log("Util unit tests:");
|
||||
|
||||
SystemLog.Instance().log("Begin RWLock test.");
|
||||
runRWLockTest();
|
||||
SystemLog.Instance().log("End RWLock test.");
|
||||
|
||||
SystemLog.Instance().log("============================");
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
public void runThreadTest()
|
||||
throws SelfTestException
|
||||
{
|
||||
|
||||
/* ####
|
||||
SystemLog.Instance().log("============================");
|
||||
SystemLog.Instance().log("Util thread test.");
|
||||
|
||||
|
||||
SystemLog.Instance().log("============================");
|
||||
*/
|
||||
}
|
||||
|
||||
public void runStressTest()
|
||||
throws SelfTestException
|
||||
{
|
||||
|
||||
/* ####
|
||||
SystemLog.Instance().log("============================");
|
||||
SystemLog.Instance().log("Util stress test.");
|
||||
|
||||
SystemLog.Instance().log("============================");
|
||||
*/
|
||||
}
|
||||
|
||||
public void runIDMapTest()
|
||||
throws SelfTestException
|
||||
{
|
||||
SelfTestIDMap.run();
|
||||
}
|
||||
|
||||
public void runAtomTest()
|
||||
throws SelfTestException
|
||||
{
|
||||
SelfTestAtom.run();
|
||||
}
|
||||
|
||||
public void runRWLockTest()
|
||||
throws SelfTestException
|
||||
{
|
||||
SelfTestRWLock.run();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
class SelfTestAtom {
|
||||
public static void run()
|
||||
throws SelfTestException
|
||||
{
|
||||
// Create a bunch of atoms
|
||||
int count = 20000;
|
||||
int[] ids = new int[count];
|
||||
String[] strings = new String[count];
|
||||
Atom[] atoms = new Atom[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
strings[i] = asciify(i);
|
||||
atoms[i] = Atom.Find(strings[i]);
|
||||
}
|
||||
|
||||
// Now verify that they act like atoms
|
||||
for (int i = 0; i < count; i++) {
|
||||
Atom atom = Atom.Find(strings[i]);
|
||||
if (atom == atoms[i]) {
|
||||
if (atom.toString() == strings[i]) {
|
||||
continue;
|
||||
}
|
||||
throw new SelfTestException("atom.toString() != strings[i]");
|
||||
} else {
|
||||
throw new SelfTestException("atom != atoms[i]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static String asciify(int i) {
|
||||
return Integer.toString(i, 16);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
/**
|
||||
* Self test exceptions are thrown when self test code is invoked
|
||||
* and fails to operate properly.
|
||||
*/
|
||||
public class SelfTestException extends Exception {
|
||||
public SelfTestException() {
|
||||
}
|
||||
|
||||
public SelfTestException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
class SelfTestIDMap {
|
||||
public static void run()
|
||||
throws SelfTestException
|
||||
{
|
||||
int count = 20000;
|
||||
int[] ids = new int[count];
|
||||
String[] strings = new String[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
strings[i] = asciify(i);
|
||||
}
|
||||
|
||||
// Fill the map
|
||||
long start = System.currentTimeMillis();
|
||||
IDMap map = new IDMap();
|
||||
for (int i = 0; i < count; i++) {
|
||||
ids[i] = map.stringToID(strings[i]);
|
||||
}
|
||||
long end = System.currentTimeMillis();
|
||||
System.out.println("stringToID: took " + (end - start) + "ms");
|
||||
|
||||
// Test the map
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < count; i++) {
|
||||
int id = map.stringToID(strings[i]);
|
||||
if (ids[i] != id) {
|
||||
throw new SelfTestException("whoops: id=" + id + " ids[i]=" + ids[i]);
|
||||
}
|
||||
}
|
||||
end = System.currentTimeMillis();
|
||||
System.out.println("stringToID: took " + (end - start) + "ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < count; i++) {
|
||||
String s = map.stringToString(strings[i]);
|
||||
if (s != strings[i]) {
|
||||
throw new SelfTestException("whoops: s=" + s + " strings[i]=" + strings[i]);
|
||||
}
|
||||
}
|
||||
end = System.currentTimeMillis();
|
||||
System.out.println("stringToString: took " + (end - start) + "ms");
|
||||
|
||||
// Verify that id's map back to strings properly
|
||||
start = System.currentTimeMillis();
|
||||
for (int i = 0; i < count; i++) {
|
||||
String s = map.idToString(ids[i]);
|
||||
if (!s.equals(strings[i])) {
|
||||
throw new SelfTestException("whoops: s=" + s + " strings[i]=" + strings[i]);
|
||||
}
|
||||
}
|
||||
end = System.currentTimeMillis();
|
||||
System.out.println("idToString: took " + (end - start) + "ms");
|
||||
}
|
||||
|
||||
static String asciify(int i) {
|
||||
return Integer.toString(i, 16);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,343 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
class SelfTestRWLock {
|
||||
static void simpleReadTest(RWLock aLock)
|
||||
throws InterruptedException
|
||||
{
|
||||
for (int i = 0; i < 5; i++) {
|
||||
aLock.enterReadLock();
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
aLock.exitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
static void simpleReadWriteTest(RWLock aLock)
|
||||
throws InterruptedException
|
||||
{
|
||||
for (int i = 0; i < 5; i++) {
|
||||
aLock.enterReadLock();
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
aLock.enterWriteLock();
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
aLock.exitWriteLock();
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
aLock.exitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
static void simpleInvariantReadTest(RWLock aLock)
|
||||
throws InterruptedException
|
||||
{
|
||||
for (int i = 0; i < 5; i++) {
|
||||
aLock.enterInvariantReadLock();
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
aLock.exitInvariantReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
static void simpleInvariantReadWriteTest(RWLock aLock)
|
||||
throws InterruptedException
|
||||
{
|
||||
for (int i = 0; i < 5; i++) {
|
||||
aLock.enterInvariantReadLock();
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
aLock.enterWriteLock();
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
aLock.exitWriteLock();
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
aLock.exitInvariantReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that an out of order exit throws an error
|
||||
static void outOfOrderExit0(RWLock aLock)
|
||||
throws InterruptedException, SelfTestException
|
||||
{
|
||||
aLock.enterReadLock();
|
||||
try {
|
||||
aLock.exitWriteLock();
|
||||
} catch (Error e) {
|
||||
return;
|
||||
}
|
||||
throw new SelfTestException("whoops");
|
||||
}
|
||||
|
||||
// Verify that an out of order exit throws an error
|
||||
static void outOfOrderExit1(RWLock aLock)
|
||||
throws InterruptedException, SelfTestException
|
||||
{
|
||||
aLock.enterReadLock();
|
||||
try {
|
||||
aLock.exitInvariantReadLock();
|
||||
} catch (Error e) {
|
||||
return;
|
||||
}
|
||||
throw new SelfTestException("whoops");
|
||||
}
|
||||
|
||||
static void outOfOrderExit2(RWLock aLock)
|
||||
throws InterruptedException, SelfTestException
|
||||
{
|
||||
aLock.enterInvariantReadLock();
|
||||
try {
|
||||
aLock.exitReadLock();
|
||||
} catch (Error e) {
|
||||
return;
|
||||
}
|
||||
throw new SelfTestException("whoops");
|
||||
}
|
||||
|
||||
static void outOfOrderExit3(RWLock aLock)
|
||||
throws InterruptedException, SelfTestException
|
||||
{
|
||||
aLock.enterInvariantReadLock();
|
||||
try {
|
||||
aLock.exitWriteLock();
|
||||
} catch (Error e) {
|
||||
return;
|
||||
}
|
||||
throw new SelfTestException("whoops");
|
||||
}
|
||||
|
||||
static void outOfOrderExit4(RWLock aLock)
|
||||
throws InterruptedException, SelfTestException
|
||||
{
|
||||
aLock.enterWriteLock();
|
||||
try {
|
||||
aLock.exitReadLock();
|
||||
} catch (Error e) {
|
||||
return;
|
||||
}
|
||||
throw new SelfTestException("whoops");
|
||||
}
|
||||
|
||||
static void outOfOrderExit5(RWLock aLock)
|
||||
throws InterruptedException, SelfTestException
|
||||
{
|
||||
aLock.enterWriteLock();
|
||||
try {
|
||||
aLock.exitInvariantReadLock();
|
||||
} catch (Error e) {
|
||||
return;
|
||||
}
|
||||
throw new SelfTestException("whoops");
|
||||
}
|
||||
|
||||
public static void run()
|
||||
throws SelfTestException
|
||||
{
|
||||
// Perform simple tests that have no contention with another thread
|
||||
try {
|
||||
simpleReadTest(new RWLock());
|
||||
simpleReadWriteTest(new RWLock());
|
||||
simpleInvariantReadTest(new RWLock());
|
||||
simpleInvariantReadWriteTest(new RWLock());
|
||||
|
||||
outOfOrderExit0(new RWLock());
|
||||
outOfOrderExit1(new RWLock());
|
||||
outOfOrderExit2(new RWLock());
|
||||
outOfOrderExit3(new RWLock());
|
||||
outOfOrderExit4(new RWLock());
|
||||
outOfOrderExit5(new RWLock());
|
||||
|
||||
verifyBlocking(new RWLock(), kRead, kWrite);
|
||||
verifyBlocking(new RWLock(), kInvariantRead, kWrite);
|
||||
verifyBlocking(new RWLock(), kWrite, kRead);
|
||||
verifyBlocking(new RWLock(), kWrite, kInvariantRead);
|
||||
|
||||
stressTestContention(new RWLock());
|
||||
} catch (InterruptedException e) {
|
||||
// Test was interrupted
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
static final int kRead = 0;
|
||||
static final int kWrite = 1;
|
||||
static final int kInvariantRead = 2;
|
||||
static String[] kStateToString = {
|
||||
"read-lock", "write-lock", "invariant-read-lock"
|
||||
};
|
||||
|
||||
// Verify that blocking is occuring by using the RWLock to
|
||||
// protect the helper.fValue and guarantee a correct ordering
|
||||
// of evaluation.
|
||||
static void verifyBlocking(RWLock aLock, int aMe, int aHelper)
|
||||
throws SelfTestException, InterruptedException
|
||||
{
|
||||
Enter(aLock, aMe);
|
||||
|
||||
RWTestHelper helper = new RWTestHelper(aLock, aHelper, 1, 1, 0);
|
||||
Thread t1 = new Thread(helper);
|
||||
t1.start();
|
||||
|
||||
// Make sure RWTestHelper is waiting to get the write-lock
|
||||
Thread.sleep(500);
|
||||
if (helper.fValue != 1) {
|
||||
throw new SelfTestException("write-lock didn't block");
|
||||
}
|
||||
|
||||
// Give RWTestHelper the lock; set value to 2 before it gets
|
||||
// the lock
|
||||
helper.fValue = 2;
|
||||
Exit(aLock, aMe);
|
||||
|
||||
// make sure RWTestHelper is done
|
||||
Thread.sleep(500);
|
||||
if (helper.fValue != 0) {
|
||||
throw new SelfTestException("helper didn't finish");
|
||||
}
|
||||
}
|
||||
|
||||
static void stressTestContention(RWLock aLock)
|
||||
throws SelfTestException, InterruptedException
|
||||
{
|
||||
int count = 500000;
|
||||
int delay = 123;
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
// Fire up a bunch of threads
|
||||
for (int i = 0; i < 3*100; i++) {
|
||||
RWTestHelper helper = new RWTestHelper(aLock, i % 3, 1, count, delay);
|
||||
Thread t = new Thread(helper);
|
||||
t.start();
|
||||
ThreadEnter();
|
||||
}
|
||||
|
||||
ThreadWait();
|
||||
long end = System.currentTimeMillis();
|
||||
System.out.println("Stress test: duration=" + (end - start) + "ms");
|
||||
}
|
||||
|
||||
static Object gThreadCounterLock = new Object();
|
||||
static int gThreadCounter;
|
||||
|
||||
static void ThreadEnter()
|
||||
throws InterruptedException
|
||||
{
|
||||
synchronized (gThreadCounterLock) {
|
||||
gThreadCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
static void ThreadExit()
|
||||
throws InterruptedException
|
||||
{
|
||||
synchronized (gThreadCounterLock) {
|
||||
if (--gThreadCounter == 0) {
|
||||
gThreadCounterLock.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ThreadWait()
|
||||
throws InterruptedException
|
||||
{
|
||||
synchronized (gThreadCounterLock) {
|
||||
while (gThreadCounter > 0) {
|
||||
gThreadCounterLock.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final boolean noisy = false;
|
||||
|
||||
static void Enter(RWLock aLock, int aHow)
|
||||
throws InterruptedException
|
||||
{
|
||||
if (noisy) {
|
||||
System.out.println(Thread.currentThread() + ": enter " +
|
||||
kStateToString[aHow]);
|
||||
}
|
||||
switch (aHow) {
|
||||
case kRead:
|
||||
aLock.enterReadLock();
|
||||
break;
|
||||
case kWrite:
|
||||
aLock.enterWriteLock();
|
||||
break;
|
||||
case kInvariantRead:
|
||||
aLock.enterInvariantReadLock();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void Exit(RWLock aLock, int aHow)
|
||||
throws InterruptedException
|
||||
{
|
||||
if (noisy) {
|
||||
System.out.println(Thread.currentThread() + ": exit " +
|
||||
kStateToString[aHow]);
|
||||
}
|
||||
switch (aHow) {
|
||||
case kRead:
|
||||
aLock.exitReadLock();
|
||||
break;
|
||||
case kWrite:
|
||||
aLock.exitWriteLock();
|
||||
break;
|
||||
case kInvariantRead:
|
||||
aLock.exitInvariantReadLock();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static class RWTestHelper implements Runnable {
|
||||
RWLock fLock;
|
||||
int fHow;
|
||||
int fValue;
|
||||
int fCount;
|
||||
int fDelay;
|
||||
|
||||
RWTestHelper(RWLock aLock, int aHow, int aValue, int aCount, int aDelay) {
|
||||
fLock = aLock;
|
||||
fHow = aHow;
|
||||
fValue = aValue;
|
||||
fCount = aCount;
|
||||
fDelay = aDelay;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
for (int i = 0; i < fCount; i++) {
|
||||
SelfTestRWLock.Enter(fLock, fHow);
|
||||
fValue /= 4;
|
||||
SelfTestRWLock.Exit(fLock, fHow);
|
||||
if ((i % 1000) == 0) {
|
||||
Thread.sleep(fDelay);
|
||||
}
|
||||
}
|
||||
SelfTestRWLock.ThreadExit();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
/**
|
||||
* Utility class that represents the parse state from parsing a
|
||||
* signed integer. The sign of the integer is maintained so that "10"
|
||||
* can be distinguished from "+10". In addition, we can optionally
|
||||
* handle numbers expressed as percentages.
|
||||
*
|
||||
* @author Kipp E.B. Hickman
|
||||
* @see Integer.parseInt
|
||||
*/
|
||||
public class SignedInteger {
|
||||
static public final int PLUS = 1;
|
||||
static public final int MINUS = -1;
|
||||
static public final int NONE = 0;
|
||||
|
||||
protected int fValue;
|
||||
protected int fSign;
|
||||
protected boolean fPct;
|
||||
|
||||
/**
|
||||
The integer part works (almost) the same as atoi():
|
||||
<ul>
|
||||
<li>Skip leading white spaces.
|
||||
<li>Non-digit char terminates convertion.
|
||||
<li>If got a valid integer, don't throw NumberFormatException.
|
||||
<li>Throw exception if first nonspace char is not digit(atoi returns 0).
|
||||
Example: " +4z" works as 4.
|
||||
*/
|
||||
// Nav 4.0 #define XP_ATOI(ss) atoi(ss)
|
||||
// Typical usage: ns\lib\layout\layutil.c lo_ValueOrPercent();
|
||||
public SignedInteger(String aString, boolean aAllowPct)
|
||||
throws NumberFormatException
|
||||
{
|
||||
if( aString == null)
|
||||
throw new NumberFormatException("1"); // Null string
|
||||
|
||||
int value = 0;
|
||||
int sign = NONE;
|
||||
int pp;
|
||||
|
||||
int len = aString.length();
|
||||
if (len == 0)
|
||||
throw new NumberFormatException("2"); // Empty string
|
||||
|
||||
//eat leading whitespace
|
||||
for(pp=0; pp<len ; pp++) {
|
||||
if( ! java.lang.Character.isWhitespace(aString.charAt(pp) ) )
|
||||
break;
|
||||
}
|
||||
|
||||
if( pp >= len )
|
||||
throw new NumberFormatException("3"); // Blank string
|
||||
|
||||
if (pp > 0 ) {
|
||||
aString = aString.substring( pp );
|
||||
len -= pp;
|
||||
}
|
||||
|
||||
if (aString.charAt(0) == '+') {
|
||||
sign = PLUS;
|
||||
aString = aString.substring(1);
|
||||
len--;
|
||||
} else if (aString.charAt(0) == '-') {
|
||||
sign = MINUS;
|
||||
aString = aString.substring(1);
|
||||
len--;
|
||||
}
|
||||
|
||||
// no white space allowed after sign.
|
||||
if( ! java.lang.Character.isDigit(aString.charAt(0)) )
|
||||
throw new NumberFormatException("4"); // start with none digit
|
||||
|
||||
// cut off nondigit at end, otherwise Integer.parseInt() will throw exception.
|
||||
for(pp=0; pp < len ; pp++) {
|
||||
if( ! java.lang.Character.isDigit(aString.charAt(pp)) )
|
||||
break;
|
||||
}
|
||||
|
||||
if( pp < len ) {
|
||||
// it has nondigit at end.
|
||||
if (aAllowPct && aString.charAt(pp) == '%' )
|
||||
fPct = true;
|
||||
// cut it off
|
||||
aString = aString.substring(0, pp );
|
||||
}
|
||||
|
||||
value = Integer.parseInt(aString, 10);
|
||||
|
||||
fValue = value;
|
||||
fSign = sign;
|
||||
if (fPct) {
|
||||
if ((fSign == MINUS) && (fValue != 0)) {
|
||||
// Negative percentages are not allowed
|
||||
throw new NumberFormatException("5"); // negative percentage
|
||||
} else if (fValue > 100) {
|
||||
// Percentages larger than 100 are quietly clamped
|
||||
fValue = 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SignedInteger(int aValue, int aSign) {
|
||||
Assert.Assertion(aValue >= 0);
|
||||
Assert.Assertion((aSign == PLUS) || (aSign == MINUS) || (aSign == NONE));
|
||||
fValue = aValue;
|
||||
fSign = aSign;
|
||||
}
|
||||
|
||||
public int intValue() {
|
||||
return fValue;
|
||||
}
|
||||
|
||||
public boolean isPct() {
|
||||
return fPct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a value based on "aBaseValue". Apply the sign of this
|
||||
* SignedInteger to determine the value to return.
|
||||
*/
|
||||
public int computeValue(int aBaseValue) {
|
||||
if (fPct) {
|
||||
return aBaseValue * fValue;
|
||||
}
|
||||
switch (fSign) {
|
||||
case PLUS:
|
||||
return aBaseValue + fValue;
|
||||
case MINUS:
|
||||
return aBaseValue - fValue;
|
||||
}
|
||||
return fValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sign of the value.
|
||||
*/
|
||||
public int getSign() {
|
||||
return fSign;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (fPct) {
|
||||
return Integer.toString(fValue, 10) + "%";
|
||||
}
|
||||
switch (fSign) {
|
||||
case PLUS:
|
||||
return "+" + Integer.toString(fValue, 10);
|
||||
case MINUS:
|
||||
return "-" + Integer.toString(fValue, 10);
|
||||
}
|
||||
return Integer.toString(fValue, 10);
|
||||
}
|
||||
// XXX equals
|
||||
// XXX hashcode
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* An enumeration to return a single element.
|
||||
*/
|
||||
public class SingleEnumeration implements Enumeration {
|
||||
Object fElement;
|
||||
boolean fSpent;
|
||||
|
||||
public SingleEnumeration(Object aElement) {
|
||||
fSpent = false;
|
||||
fElement = aElement;
|
||||
}
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
return !fSpent;
|
||||
}
|
||||
|
||||
public Object nextElement() throws NoSuchElementException {
|
||||
if (fSpent) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
else {
|
||||
fSpent = true;
|
||||
return fElement;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,742 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This class is similar to java/lang/StringBuffer with the following changes:
|
||||
* <UL><LI>None of the methods are synchronized
|
||||
* <LI>There is no sharing of the character array
|
||||
* <LI>Converting to a String requires a copy of the character data
|
||||
* <LI>Alloc and Recycle are provided to speed up allocation
|
||||
* <LI>A bunch of useful operations are provided (comparisons, etc.)
|
||||
* </UL>
|
||||
*/
|
||||
public final class StringBuf {
|
||||
private char value[];
|
||||
private int count;
|
||||
|
||||
static StringBufRecycler gRecycler;
|
||||
|
||||
/**
|
||||
* Constructs an empty String buffer, reusing one from the
|
||||
* recycler.
|
||||
*/
|
||||
static synchronized public StringBuf Alloc() {
|
||||
if (gRecycler == null) {
|
||||
gRecycler = new StringBufRecycler();
|
||||
}
|
||||
return gRecycler.alloc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Release a StringBuf to the recycler. It is up to the caller
|
||||
* to ensure that buffer is no longer being used otherwise
|
||||
* unpredicatable program behavior will result.
|
||||
*/
|
||||
static synchronized public void Recycle(StringBuf aBuf) {
|
||||
if (gRecycler == null) {
|
||||
gRecycler = new StringBufRecycler();
|
||||
}
|
||||
gRecycler.recycle(aBuf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty the recycler discarding any cached StringBuf objects
|
||||
*/
|
||||
static synchronized public void EmptyRecycler() {
|
||||
if (null != gRecycler) {
|
||||
gRecycler = null;
|
||||
}
|
||||
}
|
||||
|
||||
static void classFinalize() throws Throwable {
|
||||
// Poof! Now we are unloadable even though we have a static
|
||||
// variable.
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty String buffer.
|
||||
*/
|
||||
public StringBuf() {
|
||||
this(16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty String buffer with the specified initial length.
|
||||
* @param length the initial length
|
||||
*/
|
||||
public StringBuf(int length) {
|
||||
value = new char[length];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a String buffer with the specified initial value.
|
||||
* @param str the initial value of the buffer
|
||||
*/
|
||||
public StringBuf(String str) {
|
||||
this(str.length() + 16);
|
||||
append(str);
|
||||
}
|
||||
|
||||
public StringBuf(char chars[], int offset, int length) {
|
||||
value = new char[length];
|
||||
System.arraycopy(chars, offset, value, 0, length);
|
||||
count = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length (character count) of the buffer.
|
||||
*/
|
||||
public int length() {
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current capacity of the String buffer. The capacity
|
||||
* is the amount of storage available for newly inserted
|
||||
* characters; beyond which an allocation will occur.
|
||||
*/
|
||||
public int capacity() {
|
||||
return value.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the capacity of the buffer is at least equal to the
|
||||
* specified minimum.
|
||||
* @param minimumCapacity the minimum desired capacity
|
||||
*/
|
||||
public void ensureCapacity(int minimumCapacity) {
|
||||
int maxCapacity = value.length;
|
||||
|
||||
if (minimumCapacity > maxCapacity) {
|
||||
int newCapacity = (maxCapacity + 1) * 2;
|
||||
if (minimumCapacity > newCapacity) {
|
||||
newCapacity = minimumCapacity;
|
||||
}
|
||||
|
||||
char newValue[] = new char[newCapacity];
|
||||
System.arraycopy(value, 0, newValue, 0, count);
|
||||
value = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the length of the String. If the length is reduced, characters
|
||||
* are lost. If the length is extended, the values of the new characters
|
||||
* are set to 0.
|
||||
* @param newLength the new length of the buffer
|
||||
* @exception StringIndexOutOfBoundsException If the length is invalid.
|
||||
*/
|
||||
public void setLength(int newLength) {
|
||||
if (newLength < 0) {
|
||||
throw new StringIndexOutOfBoundsException(newLength);
|
||||
}
|
||||
ensureCapacity(newLength);
|
||||
|
||||
if (count < newLength) {
|
||||
for (; count < newLength; count++) {
|
||||
value[count] = '\0';
|
||||
}
|
||||
}
|
||||
count = newLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the content for reuse. Farster than setLength(0).
|
||||
*/
|
||||
public void setEmpty() {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the character at the specified index. An index ranges
|
||||
* from 0..length()-1.
|
||||
* @param index the index of the desired character
|
||||
* @exception StringIndexOutOfBoundsException If the index is invalid.
|
||||
*/
|
||||
public char charAt(int index) {
|
||||
if ((index < 0) || (index >= count)) {
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
}
|
||||
return value[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the characters of the specified substring (determined by
|
||||
* srcBegin and srcEnd) into the character array, starting at the
|
||||
* array's dstBegin location. Both srcBegin and srcEnd must be legal
|
||||
* indexes into the buffer.
|
||||
* @param srcBegin begin copy at this offset in the String
|
||||
* @param srcEnd stop copying at this offset in the String
|
||||
* @param dst the array to copy the data into
|
||||
* @param dstBegin offset into dst
|
||||
* @exception StringIndexOutOfBoundsException If there is an invalid index into the buffer.
|
||||
*/
|
||||
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
|
||||
if ((srcBegin < 0) || (srcBegin >= count)) {
|
||||
throw new StringIndexOutOfBoundsException(srcBegin);
|
||||
}
|
||||
if ((srcEnd < 0) || (srcEnd > count)) {
|
||||
throw new StringIndexOutOfBoundsException(srcEnd);
|
||||
}
|
||||
if (srcBegin < srcEnd) {
|
||||
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the character at the specified index to be ch.
|
||||
* @param index the index of the character
|
||||
* @param ch the new character
|
||||
* @exception StringIndexOutOfBoundsException If the index is invalid.
|
||||
*/
|
||||
public void setCharAt(int index, char ch) {
|
||||
if ((index < 0) || (index >= count)) {
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
}
|
||||
value[index] = ch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an object to the end of this buffer.
|
||||
* @param obj the object to be appended
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
*/
|
||||
public StringBuf append(Object obj) {
|
||||
return append(String.valueOf(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a String to the end of this buffer.
|
||||
* @param str the String to be appended
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
*/
|
||||
public StringBuf append(String str) {
|
||||
if (str == null) {
|
||||
str = String.valueOf(str);
|
||||
}
|
||||
|
||||
int len = str.length();
|
||||
ensureCapacity(count + len);
|
||||
str.getChars(0, len, value, count);
|
||||
count += len;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an array of characters to the end of this buffer.
|
||||
* @param str the characters to be appended
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
*/
|
||||
public StringBuf append(char str[]) {
|
||||
int len = str.length;
|
||||
ensureCapacity(count + len);
|
||||
System.arraycopy(str, 0, value, count, len);
|
||||
count += len;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StringBuf assign(char str[]) {
|
||||
count = 0;
|
||||
return( append(str) );
|
||||
}
|
||||
|
||||
public StringBuf assign(String str) {
|
||||
count = 0;
|
||||
return( append(str) );
|
||||
}
|
||||
|
||||
public StringBuf assign(char str[], int offset, int len) {
|
||||
count = 0;
|
||||
return(append( str, offset, len) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a part of an array of characters to the end of this buffer.
|
||||
* @param str the characters to be appended
|
||||
* @param offset where to start
|
||||
* @param len the number of characters to add
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
*/
|
||||
public StringBuf append(char str[], int offset, int len) {
|
||||
ensureCapacity(count + len);
|
||||
System.arraycopy(str, offset, value, count, len);
|
||||
count += len;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a boolean to the end of this buffer.
|
||||
* @param b the boolean to be appended
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
*/
|
||||
public StringBuf append(boolean b) {
|
||||
return append(String.valueOf(b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a character to the end of this buffer.
|
||||
* @param ch the character to be appended
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
*/
|
||||
public StringBuf append(char c) {
|
||||
ensureCapacity(count + 1);
|
||||
value[count++] = c;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an integer to the end of this buffer.
|
||||
* @param i the integer to be appended
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
*/
|
||||
public StringBuf append(int i) {
|
||||
return append(String.valueOf(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a long to the end of this buffer.
|
||||
* @param l the long to be appended
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
*/
|
||||
public StringBuf append(long l) {
|
||||
return append(String.valueOf(l));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a float to the end of this buffer.
|
||||
* @param f the float to be appended
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
*/
|
||||
public StringBuf append(float f) {
|
||||
return append(String.valueOf(f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a double to the end of this buffer.
|
||||
* @param d the double to be appended
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
*/
|
||||
public StringBuf append(double d) {
|
||||
return append(String.valueOf(d));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an object into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param obj the object to insert
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset is invalid.
|
||||
*/
|
||||
public StringBuf insert(int offset, Object obj) {
|
||||
return insert(offset, String.valueOf(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a String into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param str the String to insert
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset is invalid.
|
||||
*/
|
||||
public StringBuf insert(int offset, String str) {
|
||||
if ((offset < 0) || (offset > count)) {
|
||||
throw new StringIndexOutOfBoundsException();
|
||||
}
|
||||
int len = str.length();
|
||||
ensureCapacity(count + len);
|
||||
System.arraycopy(value, offset, value, offset + len, count - offset);
|
||||
str.getChars(0, len, value, offset);
|
||||
count += len;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an array of characters into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param str the characters to insert
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset is invalid.
|
||||
*/
|
||||
public StringBuf insert(int offset, char str[]) {
|
||||
if ((offset < 0) || (offset > count)) {
|
||||
throw new StringIndexOutOfBoundsException();
|
||||
}
|
||||
int len = str.length;
|
||||
ensureCapacity(count + len);
|
||||
System.arraycopy(value, offset, value, offset + len, count - offset);
|
||||
System.arraycopy(str, 0, value, offset, len);
|
||||
count += len;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a boolean into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param b the boolean to insert
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset is invalid.
|
||||
*/
|
||||
public StringBuf insert(int offset, boolean b) {
|
||||
return insert(offset, String.valueOf(b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a character into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param ch the character to insert
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset invalid.
|
||||
*/
|
||||
public StringBuf insert(int offset, char c) {
|
||||
ensureCapacity(count + 1);
|
||||
System.arraycopy(value, offset, value, offset + 1, count - offset);
|
||||
value[offset] = c;
|
||||
count += 1;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an integer into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param i the integer to insert
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset is invalid.
|
||||
*/
|
||||
public StringBuf insert(int offset, int i) {
|
||||
return insert(offset, String.valueOf(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a long into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param l the long to insert
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset is invalid.
|
||||
*/
|
||||
public StringBuf insert(int offset, long l) {
|
||||
return insert(offset, String.valueOf(l));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a float into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param f the float to insert
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset is invalid.
|
||||
*/
|
||||
public StringBuf insert(int offset, float f) {
|
||||
return insert(offset, String.valueOf(f));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a double into the String buffer.
|
||||
* @param offset the offset at which to insert
|
||||
* @param d the double to insert
|
||||
* @return the StringBuf itself, NOT a new one.
|
||||
* @exception StringIndexOutOfBoundsException If the offset is invalid.
|
||||
*/
|
||||
public StringBuf insert(int offset, double d) {
|
||||
return insert(offset, String.valueOf(d));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the order of the characters in the String buffer.
|
||||
*/
|
||||
public StringBuf reverse() {
|
||||
int n = count - 1;
|
||||
for (int j = (n-1) >> 1; j >= 0; --j) {
|
||||
char temp = value[j];
|
||||
value[j] = value[n - j];
|
||||
value[n - j] = temp;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void toUpperCase() {
|
||||
int n = count;
|
||||
for (int i = 0; i < n; i++) {
|
||||
value[i] = Character.toUpperCase(value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void toLowerCase() {
|
||||
int n = count;
|
||||
for (int i = 0; i < n; i++) {
|
||||
value[i] = Character.toLowerCase(value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts to a String representing the data in the buffer.
|
||||
*/
|
||||
public String toString() {
|
||||
return new String(value, 0, count);
|
||||
}
|
||||
|
||||
public char[] toChars() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compress the whitespace present in the buffer.
|
||||
* XXX I suppose there are i18n issues with this after all a space is
|
||||
* probably not a space...
|
||||
*/
|
||||
public void compressWhitespace(boolean aStripLeadingWhitespace) {
|
||||
int src = 0;
|
||||
int dst = 0;
|
||||
int srcEnd = count;
|
||||
while (src < srcEnd) {
|
||||
char ch = value[src];
|
||||
if (!Character.isWhitespace(ch)) {
|
||||
break;
|
||||
}
|
||||
if (!aStripLeadingWhitespace) {
|
||||
dst++;
|
||||
}
|
||||
src++;
|
||||
}
|
||||
|
||||
// Squish down any intermediate spaces
|
||||
while (src < srcEnd) {
|
||||
char ch = value[src++];
|
||||
value[dst++] = ch;
|
||||
if (!Character.isWhitespace(ch)) {
|
||||
continue;
|
||||
}
|
||||
while (src < srcEnd) {
|
||||
ch = value[src];
|
||||
if (!Character.isWhitespace(ch)) {
|
||||
break;
|
||||
}
|
||||
src++;
|
||||
}
|
||||
}
|
||||
count = dst;
|
||||
|
||||
if (count != 0) {
|
||||
// Strip out a trailing space if any. The above loop will leave
|
||||
// a single space at the end of the value if the value has any
|
||||
// trailing whitespace.
|
||||
if (Character.isWhitespace(value[count-1])) {
|
||||
count--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the string buffer contains nothing but whitespace
|
||||
* as defined by Character.isWhitespace()
|
||||
*/
|
||||
public boolean isWhitespace() {
|
||||
int n = count;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (!Character.isWhitespace(value[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this StringBuf to another String. Returns true if the
|
||||
* String is equal to this StringBuf; that is, has the same length
|
||||
* and the same characters in the same sequence. Upper case
|
||||
* characters are folded to lower case before they are compared.
|
||||
*
|
||||
* @param anotherString the String to compare this String against
|
||||
* @return true if the Strings are equal, ignoring case; false otherwise.
|
||||
*/
|
||||
public boolean equalsIgnoreCase(String anotherString) {
|
||||
return( equalsIgnoreCase( 0, count, anotherString) );
|
||||
}
|
||||
|
||||
public boolean equalsIgnoreCase(int aStart, int aLength, String anotherString) {
|
||||
if( anotherString==null ||
|
||||
aLength!=anotherString.length() ||
|
||||
aStart<0 ||
|
||||
(aStart + aLength) > count )
|
||||
return(false);
|
||||
|
||||
for (int i = 0; i < aLength; i++) {
|
||||
char c1 = value[i+aStart];
|
||||
char c2 = anotherString.charAt(i);
|
||||
if (c1 != c2) {
|
||||
// If characters don't match but case may be ignored,
|
||||
// try converting both characters to uppercase.
|
||||
// If the results match, then the comparison scan should
|
||||
// continue.
|
||||
char u1 = Character.toUpperCase(c1);
|
||||
char u2 = Character.toUpperCase(c2);
|
||||
if (u1 == u2)
|
||||
continue;
|
||||
|
||||
// Unfortunately, conversion to uppercase does not work properly
|
||||
// for the Georgian alphabet, which has strange rules about case
|
||||
// conversion. So we need to make one last check before
|
||||
// exiting.
|
||||
if (Character.toLowerCase(u1) == Character.toLowerCase(u2))
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this StringBuf to another StringBuf. Returns true if the
|
||||
* other StringBuf is equal to this StringBuf; that is, has the same length
|
||||
* and the same characters in the same sequence. Upper case
|
||||
* characters are folded to lower case before they are compared.
|
||||
*
|
||||
* @param anotherString the String to compare this String against
|
||||
* @return true if the Strings are equal, ignoring case; false otherwise.
|
||||
*/
|
||||
public boolean equalsIgnoreCase(StringBuf anotherString) {
|
||||
if ((anotherString != null) && (anotherString.count == count)) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
char c1 = value[i];
|
||||
char c2 = anotherString.value[i];
|
||||
if (c1 != c2) {
|
||||
// If characters don't match but case may be ignored,
|
||||
// try converting both characters to uppercase.
|
||||
// If the results match, then the comparison scan should
|
||||
// continue.
|
||||
char u1 = Character.toUpperCase(c1);
|
||||
char u2 = Character.toUpperCase(c2);
|
||||
if (u1 == u2)
|
||||
continue;
|
||||
|
||||
// Unfortunately, conversion to uppercase does not work properly
|
||||
// for the Georgian alphabet, which has strange rules about case
|
||||
// conversion. So we need to make one last check before
|
||||
// exiting.
|
||||
if (Character.toLowerCase(u1) == Character.toLowerCase(u2))
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean equals(Object aObject) {
|
||||
if (aObject != null) {
|
||||
if (aObject instanceof StringBuf) {
|
||||
return equals((StringBuf) aObject);
|
||||
} else if (aObject instanceof String) {
|
||||
return equals((String) aObject);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this StringBuf to another StringBuf. Returns true if the
|
||||
* other StringBuf is equal to this StringBuf; that is, has the same length
|
||||
* and the same characters in the same sequence.
|
||||
*
|
||||
* @param anotherString the String to compare this String against
|
||||
* @return true if the Strings are equal, ignoring case; false otherwise.
|
||||
*/
|
||||
public boolean equals(StringBuf anotherString) {
|
||||
if ((anotherString != null) && (anotherString.count == count)) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
char c1 = value[i];
|
||||
char c2 = anotherString.value[i];
|
||||
if (c1 != c2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this StringBuf to another String. Returns true if the
|
||||
* other String is equal to this StringBuf; that is, has the same length
|
||||
* and the same characters in the same sequence.
|
||||
*
|
||||
* @param anotherString the String to compare this String against
|
||||
* @return true if the Strings are equal, ignoring case; false otherwise.
|
||||
*/
|
||||
public boolean equals(String anotherString) {
|
||||
if ((anotherString != null) && (anotherString.length() == count)) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
char c1 = value[i];
|
||||
char c2 = anotherString.charAt(i);
|
||||
if (c1 != c2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int indexOf(int ch) {
|
||||
return indexOf(ch, 0);
|
||||
}
|
||||
|
||||
public int indexOf(int ch, int fromIndex) {
|
||||
int max = count;
|
||||
char v[] = value;
|
||||
|
||||
if (fromIndex < 0) {
|
||||
fromIndex = 0;
|
||||
} else if (fromIndex >= count) {
|
||||
// Note: fromIndex might be near -1>>>1.
|
||||
return -1;
|
||||
}
|
||||
for (int i = fromIndex ; i < max ; i++) {
|
||||
if (v[i] == ch) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void remove(int fromIndex) {
|
||||
remove(fromIndex, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove characters from the StringBuf starting at fromIndex and up
|
||||
* to but not including toIndex. If toIndex is beyond the length of
|
||||
* the StringBuf then it is automatically clamped to the end of the
|
||||
* StringBuf. If fromIndex is out of range a StringIndexOutOfBoundsException
|
||||
* is thrown.
|
||||
*/
|
||||
public void remove(int fromIndex, int toIndex) {
|
||||
if ((fromIndex >= toIndex) || (fromIndex >= count)) {
|
||||
throw new StringIndexOutOfBoundsException(fromIndex);
|
||||
}
|
||||
if (toIndex > count) toIndex = count;
|
||||
if (toIndex == count) {
|
||||
count = fromIndex;
|
||||
return;
|
||||
}
|
||||
System.arraycopy(value, toIndex, value, fromIndex, count - toIndex);
|
||||
count -= toIndex - fromIndex;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
class StringBufRecycler extends Recycler
|
||||
{
|
||||
|
||||
/********************************************************
|
||||
* @author gess 04-16-97 2:02pm
|
||||
* @param
|
||||
* @return
|
||||
* @notes This subclass of the recycler can actually
|
||||
manufacture instances of stringbuf. This is
|
||||
behavior that the standard recycler doesn't do,
|
||||
and the I expect will change in this class,
|
||||
real soon now.
|
||||
*********************************************************/
|
||||
StringBuf alloc()
|
||||
{
|
||||
StringBuf result=null;
|
||||
if (fCount>0)
|
||||
{
|
||||
result = (StringBuf)fBuffer[fCount-1];
|
||||
fBuffer[--fCount]=null;
|
||||
result.setLength(0);
|
||||
}
|
||||
else result=new StringBuf();
|
||||
return result;
|
||||
}
|
||||
|
||||
public void panic()
|
||||
{
|
||||
// Get rid of everything, including ourselves
|
||||
super.panic();
|
||||
StringBuf.gRecycler = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
public class StringUtils {
|
||||
/**
|
||||
* Uppercase the characters in aString.
|
||||
*
|
||||
* @see: java.lang.Character
|
||||
*/
|
||||
static public String UpperCase(String aString) {
|
||||
StringBuf buf = StringBuf.Alloc();
|
||||
buf.append(aString);
|
||||
buf.toUpperCase();
|
||||
aString = buf.toString();
|
||||
StringBuf.Recycle(buf);
|
||||
return aString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lowercase the characters in aString.
|
||||
*
|
||||
* @see: java.lang.Character
|
||||
*/
|
||||
static public String LowerCase(String aString) {
|
||||
StringBuf buf = StringBuf.Alloc();
|
||||
buf.append(aString);
|
||||
buf.toLowerCase();
|
||||
aString = buf.toString();
|
||||
StringBuf.Recycle(buf);
|
||||
return aString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the string buffer contains nothing but whitespace
|
||||
* as defined by Character.isWhitespace()
|
||||
*
|
||||
* @see: java.lang.Character
|
||||
*/
|
||||
static public boolean IsWhitespace(String aString) {
|
||||
// XXX this should just loop right here instead of copying
|
||||
// the string because the loop will be inlined with a good
|
||||
// compiler
|
||||
StringBuf buf = StringBuf.Alloc();
|
||||
buf.append(aString);
|
||||
boolean rv = buf.isWhitespace();
|
||||
StringBuf.Recycle(buf);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate an integer into a string that is at least aDigits
|
||||
* wide. Pad with zeros if necessary.
|
||||
*/
|
||||
static public String ToHex(int i, int aDigits) {
|
||||
String rv = Integer.toString(i, 16);
|
||||
int len = rv.length();
|
||||
if (len < aDigits) {
|
||||
StringBuf buf = StringBuf.Alloc();
|
||||
len = aDigits - len;
|
||||
while (--len >= 0) {
|
||||
buf.append('0');
|
||||
}
|
||||
buf.append(rv);
|
||||
rv = buf.toString();
|
||||
StringBuf.Recycle(buf);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compress the whitespace out of a string and return a new string
|
||||
*/
|
||||
static public String CompressWhitespace(String aString, boolean aLeading) {
|
||||
StringBuf buf = StringBuf.Alloc();
|
||||
buf.append(aString);
|
||||
buf.compressWhitespace(aLeading);
|
||||
String rv = buf.toString();
|
||||
StringBuf.Recycle(buf);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quote a string using java source file rules. The result is a new
|
||||
* string with all the appropriate data quoted. The outer quotes that
|
||||
* would be required in a java source file are not provided by this
|
||||
* routine unless aProvideOuterQuotes is true.
|
||||
*/
|
||||
static char[] hex;
|
||||
static {
|
||||
hex = new char[16];
|
||||
"0123456789abcdef".getChars(0, 16, hex, 0);
|
||||
}
|
||||
static public String JavaQuote(String aString, boolean aProvideOuterQuotes)
|
||||
{
|
||||
StringBuf buf = StringBuf.Alloc();
|
||||
if (aProvideOuterQuotes) {
|
||||
buf.append('"');
|
||||
}
|
||||
for (int i = 0, n = aString.length(); i < n; i++) {
|
||||
char ch = aString.charAt(i);
|
||||
switch (ch) {
|
||||
case '\n':
|
||||
buf.append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
buf.append("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
buf.append("\\t");
|
||||
break;
|
||||
case '"':
|
||||
buf.append("\\\"");
|
||||
break;
|
||||
default:
|
||||
if ((ch < 32) || (ch >= 127)) {
|
||||
buf.append("\\u");
|
||||
buf.append(hex[(ch >> 12) & 0xf]);
|
||||
buf.append(hex[(ch >> 8) & 0xf]);
|
||||
buf.append(hex[(ch >> 4) & 0xf]);
|
||||
buf.append(hex[ch & 0xf]);
|
||||
} else {
|
||||
buf.append(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (aProvideOuterQuotes) {
|
||||
buf.append('"');
|
||||
}
|
||||
String rv = buf.toString();
|
||||
StringBuf.Recycle(buf);
|
||||
return rv;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Utility class for generating temporary file names.
|
||||
*
|
||||
* @author Kipp E.B. Hickman
|
||||
*/
|
||||
public class TempFile {
|
||||
static private boolean gHaveSetFinalizersOnExit;
|
||||
static private int gNextID;
|
||||
static private Random gGenerator = new Random();
|
||||
|
||||
String fTempFileName;
|
||||
|
||||
/**
|
||||
* Create a new temporary file name that the calling
|
||||
* thread can use that is unique and has the given extension.
|
||||
*/
|
||||
// XXX need security access check
|
||||
static public synchronized TempFile TempName(String aExtension) {
|
||||
/* XXX seems to cause jdk1.1.3b to hang...
|
||||
if (!gHaveSetFinalizersOnExit) {
|
||||
// Make sure temp files get removed on exit
|
||||
System.runFinalizersOnExit(true);
|
||||
gHaveSetFinalizersOnExit = true;
|
||||
}*/
|
||||
|
||||
// Fix up temp dir to have a trailing separator
|
||||
String tmpDir = GetTempDir();
|
||||
int tmpDirLen = tmpDir.length();
|
||||
if ((tmpDirLen > 0) &&
|
||||
(tmpDir.charAt(tmpDirLen - 1) != File.separatorChar)) {
|
||||
tmpDir = tmpDir + File.separatorChar;
|
||||
SetTempDir(tmpDir);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
int value = gGenerator.nextInt() & 0xffffff;
|
||||
String name = tmpDir + "ns" + StringUtils.ToHex(value, 6) + aExtension;
|
||||
File file = new File(name);
|
||||
if (file.exists()) {
|
||||
continue;
|
||||
}
|
||||
return new TempFile(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the native path name for the system's temporary directory.
|
||||
*/
|
||||
static final String propertyName = "system.tempdir";
|
||||
static public synchronized String GetTempDir() {
|
||||
Properties p = System.getProperties();
|
||||
String dir = p.getProperty(propertyName);
|
||||
if (dir == null) {
|
||||
String osname = p.getProperty("os.name");
|
||||
if (osname.startsWith("Windows")) {
|
||||
dir = "c:\\windows\temp";
|
||||
if (TryDirectory(dir)) {
|
||||
return dir;
|
||||
}
|
||||
dir = "c:\\temp";
|
||||
if (TryDirectory(dir)) {
|
||||
return dir;
|
||||
}
|
||||
dir = "\temp";
|
||||
if (TryDirectory(dir)) {
|
||||
return dir;
|
||||
}
|
||||
dir = "\tmp";
|
||||
if (TryDirectory(dir)) {
|
||||
return dir;
|
||||
}
|
||||
// Oh well, fall back to the current directory wherever that is!
|
||||
dir = ".";
|
||||
if (TryDirectory(dir)) {
|
||||
return dir;
|
||||
}
|
||||
throw new Error("whoops: no windoze tempdir!");
|
||||
} else {
|
||||
// XXX for now, assume it's unix
|
||||
dir = "/tmp";
|
||||
if (TryDirectory(dir)) {
|
||||
return dir;
|
||||
}
|
||||
throw new Error("whoops: no unix tempdir!");
|
||||
}
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
static private boolean TryDirectory(String aDir) {
|
||||
File f = new File(aDir);
|
||||
if (f.exists() && f.isDirectory()) {
|
||||
SetTempDir(aDir);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the native path name for the system's temporary directory.
|
||||
*/
|
||||
// XXX need security access check
|
||||
static public synchronized void SetTempDir(String aDir) {
|
||||
Properties p = System.getProperties();
|
||||
p.put(propertyName, aDir);
|
||||
}
|
||||
|
||||
protected TempFile(String aName) {
|
||||
fTempFileName = aName;
|
||||
}
|
||||
|
||||
public OutputStream create() throws IOException {
|
||||
return new BufferedOutputStream(new FileOutputStream(fTempFileName));
|
||||
}
|
||||
|
||||
public OutputStream append() throws IOException {
|
||||
return new BufferedOutputStream(new FileOutputStream(fTempFileName, true));
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return fTempFileName;
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
if (fTempFileName != null) {
|
||||
new File(fTempFileName).delete();
|
||||
fTempFileName = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
delete();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
// original timebomb code to search for.
|
||||
|
||||
// This will expire on April 1st at 12pm local time
|
||||
//java.util.Date before = new Date(97, 9, 1, 0, 0);
|
||||
//java.util.Date now = new Date();
|
||||
//java.util.Date then = new Date(97, 11, 25, 12, 00);
|
||||
//if (now.before(before) || now.after(then)) {
|
||||
// System.err.println("This software has expired");
|
||||
// System.exit(-1);
|
||||
//}
|
||||
|
||||
public class TimeBomb
|
||||
{
|
||||
public static final boolean Ticking = true;
|
||||
|
||||
// Before is 12-01-97
|
||||
|
||||
public static final int BeforeYear = 97;
|
||||
public static final int BeforeMonth = 11; // Zero based
|
||||
public static final int BeforeDate = 1;
|
||||
|
||||
// Expire is 4-01-98
|
||||
|
||||
public static final int ExpiresYear = 98;
|
||||
public static final int ExpiresMonth = 3; // Zero based
|
||||
public static final int ExpiresDate = 1;
|
||||
public static final int ExpiresHour = 12;
|
||||
}
|
|
@ -0,0 +1,341 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import java.io.*;
|
||||
|
||||
// Simple class loader:
|
||||
// - no signatures
|
||||
// - no security
|
||||
// - no mayscript
|
||||
|
||||
/**
|
||||
* A URL based class loader. This class knows how to load classes from
|
||||
* a given base URL
|
||||
*/
|
||||
public class URLClassLoader extends ClassLoader {
|
||||
private Hashtable classes;
|
||||
private URL codeBaseURL;
|
||||
private URL archiveURL;
|
||||
private ZipFile fZipFile;
|
||||
private TempFile fTempFile;
|
||||
|
||||
static final boolean XXXnoisy = false;
|
||||
|
||||
/**
|
||||
* Create a new URL based class loader. aBaseURL specifies the URL
|
||||
* to load classes relative to. If aArchiveURL is not null then the
|
||||
* archive will be searched first (if it fails then the load will be
|
||||
* attempted from aBaseURL).
|
||||
*/
|
||||
public URLClassLoader(URL aBaseURL, URL aArchiveURL) {
|
||||
codeBaseURL = aBaseURL;
|
||||
archiveURL = aArchiveURL;
|
||||
classes = new Hashtable();
|
||||
if (XXXnoisy) {
|
||||
System.out.println("####### Creating TagClassLoader");
|
||||
System.out.println("### CodeBaseURL=" + codeBaseURL);
|
||||
System.out.println("### ArchiveURL=" + archiveURL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a class from a URL. This does the actual work of loading the
|
||||
* class and then defining it.
|
||||
*/
|
||||
private Class loadClass(String name, URL url, String pathname)
|
||||
throws IOException
|
||||
{
|
||||
byte[] data = readURL(url);
|
||||
if (XXXnoisy) {
|
||||
System.out.println("# loadClass: url="+url+" bytes="+data.length);
|
||||
}
|
||||
// XXX update for netscape security model
|
||||
return defineClass(name, data, 0, data.length);
|
||||
}
|
||||
|
||||
private Class loadClassFromArchive(String name, URL url, String pathname)
|
||||
throws IOException
|
||||
{
|
||||
if (fZipFile == null) {
|
||||
// First time in we copy over the archive URL
|
||||
fTempFile = TempFile.TempName(".zip");
|
||||
copyURL(fTempFile.create(), url);
|
||||
if (XXXnoisy) {
|
||||
System.out.println("### Copying zip file: tempName=" +
|
||||
fTempFile.getName() + " url=" + url);
|
||||
}
|
||||
fZipFile = new ZipFile(fTempFile.getName());
|
||||
}
|
||||
|
||||
// Dig up the class's bits using the zip loader
|
||||
byte[] data = readZipFile(pathname);
|
||||
if (XXXnoisy) {
|
||||
System.out.println("# loadClass: url="+url+"(" +
|
||||
pathname + ") bytes=" + data.length);
|
||||
}
|
||||
// XXX update for netscape security model
|
||||
return defineClass(name, data, 0, data.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a class from this class loader. This method is used by applets
|
||||
* that want to explicitly load a class.
|
||||
*/
|
||||
public Class loadClass(String name) throws ClassNotFoundException {
|
||||
return loadClass(name, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and resolve a class. This method is called by the java runtime
|
||||
* to get a class that another class needs (e.g. a superclass).
|
||||
*/
|
||||
protected Class loadClass(String name, boolean resolve)
|
||||
throws ClassNotFoundException
|
||||
{
|
||||
Class cl = (Class)classes.get(name);
|
||||
if (cl == null) {
|
||||
// XXX: We should call a Security.checksPackageAccess() native
|
||||
// method, and pass name as arg
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) {
|
||||
int i = name.lastIndexOf('.');
|
||||
if (i >= 0) {
|
||||
security.checkPackageAccess(name.substring(0, i));
|
||||
}
|
||||
}
|
||||
try {
|
||||
return findSystemClass(name);
|
||||
} catch (ClassNotFoundException e) {
|
||||
}
|
||||
cl = findClass(name);
|
||||
}
|
||||
if (cl == null) {
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
if (resolve) {
|
||||
resolveClass(cl);
|
||||
}
|
||||
return cl;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method finds a class. The returned class
|
||||
* may be unresolved. This method has to be synchronized
|
||||
* to avoid two threads loading the same class at the same time.
|
||||
* Must be called with the actual class name.
|
||||
*/
|
||||
private synchronized Class findClass(String name)
|
||||
throws ClassNotFoundException
|
||||
{
|
||||
Class cl = (Class)classes.get(name);
|
||||
if (cl != null) {
|
||||
return cl;
|
||||
}
|
||||
|
||||
// XXX: We should call a Security.checksPackageDefinition() native
|
||||
// method, and pass name as arg
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) {
|
||||
int i = name.lastIndexOf('.');
|
||||
if (i >= 0) {
|
||||
security.checkPackageDefinition(name.substring(0, i));
|
||||
}
|
||||
}
|
||||
|
||||
boolean system_class = true;
|
||||
String cname = name.replace('.', '/') + ".class";
|
||||
if (cl == null) {
|
||||
URL url;
|
||||
try {
|
||||
url = new URL(codeBaseURL, cname);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
if (XXXnoisy) {
|
||||
System.err.println("# Fetching " + url);
|
||||
}
|
||||
|
||||
try {
|
||||
if (archiveURL != null) {
|
||||
cl = loadClassFromArchive(name, archiveURL, cname);
|
||||
// XXX try regular file if archive load fails?
|
||||
} else {
|
||||
cl = loadClass(name, url, cname);
|
||||
}
|
||||
system_class = false;
|
||||
} catch (IOException e) {
|
||||
if (XXXnoisy) {
|
||||
System.out.println("# IOException loading class: " + e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
}
|
||||
if (!name.equals(cl.getName())) {
|
||||
Class oldcl = cl;
|
||||
cl = null;
|
||||
throw new ClassFormatError(name + " != " + oldcl.getName());
|
||||
}
|
||||
if (system_class == false) {
|
||||
// setPrincipalAry(cl, cname);
|
||||
}
|
||||
classes.put(name, cl);
|
||||
return cl;
|
||||
}
|
||||
|
||||
// collapse the i/o loops between this code and readZipFile
|
||||
|
||||
private byte[] readURL(URL url) throws IOException {
|
||||
byte[] data;
|
||||
InputStream in = null;
|
||||
try {
|
||||
URLConnection c = url.openConnection();
|
||||
c.setAllowUserInteraction(false);
|
||||
in = c.getInputStream();
|
||||
|
||||
int len = c.getContentLength();
|
||||
data = new byte[(len == -1) ? 4096 : len];
|
||||
int total = 0, n;
|
||||
|
||||
while ((n = in.read(data, total, data.length - total)) >= 0) {
|
||||
if ((total += n) == data.length) {
|
||||
if (len < 0) {
|
||||
byte newdata[] = new byte[total * 2];
|
||||
System.arraycopy(data, 0, newdata, 0, total);
|
||||
data = newdata;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a given file from the underlying zip file named "aName". Return
|
||||
* an array of bytes which contain the decompressed contents of the
|
||||
* file in the zip file.
|
||||
*/
|
||||
private byte[] readZipFile(String aName)
|
||||
throws IOException
|
||||
{
|
||||
ZipEntry entry = fZipFile.getEntry(aName);
|
||||
if (entry == null) {
|
||||
throw new IOException("file not found: " + aName);
|
||||
}
|
||||
|
||||
InputStream in = null;
|
||||
int len = (int) entry.getSize();
|
||||
byte[] data = new byte[(len == -1) ? 4096 : len];
|
||||
try {
|
||||
in = fZipFile.getInputStream(entry);
|
||||
int total = 0, n;
|
||||
while ((n = in.read(data, total, data.length - total)) >= 0) {
|
||||
if ((total += n) == data.length) {
|
||||
if (len < 0) {
|
||||
byte newdata[] = new byte[total * 2];
|
||||
System.arraycopy(data, 0, newdata, 0, total);
|
||||
data = newdata;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private void copyURL(OutputStream aOut, URL aURLSource)
|
||||
throws IOException
|
||||
{
|
||||
InputStream in = null;
|
||||
try {
|
||||
byte[] inputBuf = new byte[4096];
|
||||
|
||||
// open the destination file for writing
|
||||
//SecurityManager.enablePrivilege("UniversalFileAccess");
|
||||
//SecurityManager.enablePrivilege("UniversalConnect");
|
||||
|
||||
URLConnection c = archiveURL.openConnection();
|
||||
c.setAllowUserInteraction(false);
|
||||
in = c.getInputStream();
|
||||
|
||||
// Read all the bytes from the url into the temp file
|
||||
Thread thread = Thread.currentThread();
|
||||
int total = 0, n;
|
||||
while (((n = in.read(inputBuf)) >= 0) && !thread.isInterrupted()) {
|
||||
aOut.write(inputBuf, 0, n);
|
||||
total += n;
|
||||
}
|
||||
if (thread.isInterrupted()) {
|
||||
throw new IOException("interrupted: " + this);
|
||||
}
|
||||
if (XXXnoisy) {
|
||||
System.out.println("# Copying archive: url=" + archiveURL +
|
||||
" tempFile=" + fTempFile.getName() +
|
||||
" copiedBytes=" + total);
|
||||
}
|
||||
} finally {
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
if (aOut != null) {
|
||||
aOut.close();
|
||||
}
|
||||
}
|
||||
// SecurityManager.revertPrivilege();
|
||||
}
|
||||
|
||||
public URL getCodeBaseURL() {
|
||||
return codeBaseURL;
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
if (fZipFile != null) {
|
||||
try {
|
||||
// First close the zip file
|
||||
fZipFile.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
fZipFile = null;
|
||||
}
|
||||
if (fTempFile != null) {
|
||||
try {
|
||||
// Then remove the temporary file
|
||||
fTempFile.delete();
|
||||
} finally {
|
||||
fTempFile = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Some more methods for Vector
|
||||
*/
|
||||
public class Vec extends Vector {
|
||||
public Vec(int initialCapacity, int capacityIncrement) {
|
||||
super(initialCapacity, capacityIncrement);
|
||||
}
|
||||
|
||||
public Vec(int initialCapacity) {
|
||||
super(initialCapacity, 0);
|
||||
}
|
||||
|
||||
public Vec() {
|
||||
}
|
||||
|
||||
public boolean containsIdentical(Object aElement) {
|
||||
return indexOfIdentical(aElement, 0) != -1;
|
||||
}
|
||||
|
||||
public int indexOfIdentical(Object aElement) {
|
||||
return indexOfIdentical(aElement, 0);
|
||||
}
|
||||
|
||||
public synchronized int indexOfIdentical(Object aElement, int aIndex) {
|
||||
for (int i = aIndex; i < elementCount ; i++) {
|
||||
if (aElement == elementData[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public boolean insertElementAfter(Object aElement, Object aExistingElement)
|
||||
{
|
||||
if (aElement == null) {
|
||||
throw new NullPointerException(
|
||||
"It is illegal to store nulls in Vectors.");
|
||||
}
|
||||
if (aExistingElement == null) {
|
||||
return false;
|
||||
}
|
||||
int index = indexOf(aExistingElement);
|
||||
if (index == -1) {
|
||||
return false;
|
||||
}
|
||||
if (index >= elementCount - 1) {
|
||||
addElement(aElement);
|
||||
} else {
|
||||
insertElementAt(aElement, index + 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void addElements(Vector aVector) {
|
||||
int addCount, i;
|
||||
|
||||
if (aVector == null)
|
||||
return;
|
||||
addCount = aVector.size();
|
||||
if (elementData == null || (elementCount + addCount) >= elementData.length)
|
||||
ensureCapacity(elementCount + addCount);
|
||||
|
||||
for (i = 0; i < addCount; i++)
|
||||
addElement(aVector.elementAt(i));
|
||||
}
|
||||
|
||||
public synchronized boolean removeElementIdentical(Object aElement) {
|
||||
int i = indexOfIdentical(aElement);
|
||||
if (i >= 0) {
|
||||
removeElementAt(i);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public synchronized Object removeFirstElement() {
|
||||
if (elementCount == 0) {
|
||||
return null;
|
||||
}
|
||||
Object rv = elementData[0];
|
||||
removeElementAt(0);
|
||||
return rv;
|
||||
}
|
||||
|
||||
public synchronized Object removeLastElement() {
|
||||
if (elementCount == 0) {
|
||||
return null;
|
||||
}
|
||||
int index = elementCount - 1;
|
||||
Object rv = elementData[index];
|
||||
removeElementAt(index);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static Comparer gStringComparer;
|
||||
|
||||
public synchronized void sort() {
|
||||
if (gStringComparer == null) {
|
||||
gStringComparer = new StringComparer();
|
||||
}
|
||||
QSort s = new QSort(gStringComparer);
|
||||
s.sort(elementData, 0, elementCount);
|
||||
}
|
||||
|
||||
public synchronized void sort(Comparer aComparer) {
|
||||
QSort s = new QSort(aComparer);
|
||||
s.sort(elementData, 0, elementCount);
|
||||
}
|
||||
|
||||
static class StringComparer implements Comparer {
|
||||
public int compare(Object a, Object b) {
|
||||
return ((String)a).compareTo((String)b);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Static recycler class for java.util.Vector
|
||||
*
|
||||
* @author psl 04-23-97 6:51pm
|
||||
* @see
|
||||
*/
|
||||
public final class VectorRecycler
|
||||
{
|
||||
static Recycler gRecycler;
|
||||
|
||||
/**
|
||||
* Get one
|
||||
*
|
||||
* @return
|
||||
* @exception
|
||||
* @author psl 04-23-97 6:52pm
|
||||
*/
|
||||
public static synchronized Vector Alloc ()
|
||||
{
|
||||
Vector result = null;
|
||||
|
||||
if (null != gRecycler)
|
||||
result = (Vector)gRecycler.getRecycledObject ();
|
||||
if (null == result)
|
||||
result = new Vector ();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get one with an initial capacity
|
||||
* <I>a recycled vector may be bigger than capacity</I>
|
||||
*
|
||||
* @param aCapacity minimum desired capacity
|
||||
* @return
|
||||
* @exception
|
||||
* @author psl 04-23-97 6:52pm
|
||||
*/
|
||||
public static synchronized Vector Alloc (int aCapacity)
|
||||
{
|
||||
Vector result = null;
|
||||
|
||||
if (null != gRecycler)
|
||||
result = (Vector)gRecycler.getRecycledObject ();
|
||||
if (null != result)
|
||||
result.ensureCapacity (aCapacity);
|
||||
else
|
||||
result = new Vector (aCapacity);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recycle a vector
|
||||
* (it will be emptied by the recycler)
|
||||
*
|
||||
* @param aVector vector to be recycled
|
||||
* @return
|
||||
* @exception
|
||||
* @author psl 04-23-97 6:52pm
|
||||
*/
|
||||
public static synchronized void Recycle (Vector aVector)
|
||||
{
|
||||
if (null == gRecycler)
|
||||
gRecycler = new Recycler ();
|
||||
aVector.removeAllElements ();
|
||||
gRecycler.recycle (aVector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty the recycler, it's earth day
|
||||
*
|
||||
* @param
|
||||
* @return
|
||||
* @exception
|
||||
* @author psl 04-21-97 4:29pm
|
||||
*/
|
||||
static synchronized public void EmptyRecycler ()
|
||||
{
|
||||
if (null != gRecycler)
|
||||
gRecycler.empty ();
|
||||
}
|
||||
|
||||
/**
|
||||
* finalize class for unloading
|
||||
*
|
||||
* @param
|
||||
* @return
|
||||
* @exception
|
||||
* @author psl 04-21-97 4:29pm
|
||||
*/
|
||||
static void classFinalize () throws Throwable
|
||||
{
|
||||
// Poof! Now we are unloadable even though we have a static
|
||||
// variable.
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import sun.misc.Ref;
|
||||
|
||||
/**
|
||||
* Weak link class.
|
||||
*/
|
||||
public class WeakLink extends sun.misc.Ref {
|
||||
public WeakLink() {
|
||||
}
|
||||
|
||||
public WeakLink(Object obj) {
|
||||
setThing(obj);
|
||||
}
|
||||
|
||||
public Object reconstitute() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* An array of objects whose references are weak. Weak references
|
||||
* hold a reference to the object that the GC can break when the
|
||||
* object no longer has any hard references.
|
||||
*/
|
||||
public class WeakLinkArray {
|
||||
WeakLink fArray[];
|
||||
int fCount;
|
||||
|
||||
public WeakLinkArray() {
|
||||
}
|
||||
|
||||
public void addElement(Object aObject) {
|
||||
if (fArray == null) {
|
||||
fArray = new WeakLink[10];
|
||||
} else {
|
||||
// Grow the array if it's too small
|
||||
int len = fArray.length;
|
||||
if (fCount == len) {
|
||||
// Try to use a slot in the array that contains a dead weak
|
||||
// link instead of growing the array.
|
||||
for (int i = 0; i < fCount; i++) {
|
||||
WeakLink w = fArray[i];
|
||||
if ((w == null) || (w.get() == null)) {
|
||||
if (w == null) {
|
||||
fArray[i] = new WeakLink(aObject);
|
||||
} else {
|
||||
w.setThing(aObject);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Grow the array.
|
||||
len += 10;
|
||||
WeakLink newArray[] = new WeakLink[len];
|
||||
System.arraycopy(fArray, 0, newArray, 0, fCount);
|
||||
fArray = newArray;
|
||||
}
|
||||
}
|
||||
fArray[fCount++] = new WeakLink(aObject);
|
||||
}
|
||||
|
||||
public void removeElement(Object aObject) {
|
||||
int n = fCount;
|
||||
for (int i = 0; i < n; i++) {
|
||||
WeakLink w = fArray[i];
|
||||
if (w != null) {
|
||||
Object obj = w.get();
|
||||
if ((obj == null) || (obj == aObject)) {
|
||||
fArray[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(Object aObject) {
|
||||
int n = fCount;
|
||||
for (int i = 0; i < n; i++) {
|
||||
WeakLink w = fArray[i];
|
||||
if ((w != null) && (w.get() == aObject)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Enumeration elements() {
|
||||
return new WeakLinkArrayEnumeration(this);
|
||||
}
|
||||
// XXX hashCode, equals, toString
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package calypso.util;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
class WeakLinkArrayEnumeration implements Enumeration {
|
||||
WeakLink fArray[];
|
||||
int fCount;
|
||||
int fOffset;
|
||||
|
||||
WeakLinkArrayEnumeration(WeakLinkArray aArray) {
|
||||
fArray = aArray.fArray;
|
||||
fCount = aArray.fCount;
|
||||
}
|
||||
|
||||
public boolean hasMoreElements() {
|
||||
return fOffset < fCount;
|
||||
}
|
||||
|
||||
public Object nextElement() {
|
||||
if (fOffset == fCount) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return fArray[fOffset++];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package grendel.composition;
|
||||
|
||||
import java.awt.*;
|
||||
import com.sun.java.swing.*;
|
||||
|
||||
public class AddressBar extends NSTabbedPane {
|
||||
AddressList mAddressList;
|
||||
AttachmentsList mAttachmentsList;
|
||||
OptionsPanel mOptionsPanel;
|
||||
|
||||
public AddressBar() {
|
||||
//address panel
|
||||
ImageIcon addressIcon = new ImageIcon(getClass().getResource("images/small_address.gif"));
|
||||
mAddressList = new AddressList ();
|
||||
|
||||
//attachments panel
|
||||
ImageIcon attachmentsIcon = new ImageIcon(getClass().getResource("images/small_attachments.gif"));
|
||||
mAttachmentsList = new AttachmentsList();
|
||||
|
||||
//otpions panel
|
||||
ImageIcon optionsIcon = new ImageIcon(getClass().getResource("images/small_otpions.gif"));
|
||||
mOptionsPanel = new OptionsPanel();
|
||||
|
||||
//tabbed panel holds address, attachments and otpions.
|
||||
addTab("", addressIcon, mAddressList);
|
||||
addTab("", attachmentsIcon, mAttachmentsList);
|
||||
addTab("", optionsIcon, mOptionsPanel);
|
||||
setSelectedIndex(0);
|
||||
}
|
||||
|
||||
public AddressList getAddressList() {
|
||||
return mAddressList;
|
||||
}
|
||||
|
||||
public AttachmentsList getAttachmentsList() {
|
||||
return mAttachmentsList;
|
||||
}
|
||||
|
||||
public OptionsPanel getOptionsPanel() {
|
||||
return mOptionsPanel;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,389 @@
|
|||
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.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.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is the Grendel mail/news client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package grendel.composition;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.*;
|
||||
|
||||
import com.sun.java.swing.*;
|
||||
import com.sun.java.swing.table.*;
|
||||
import com.sun.java.swing.border.*;
|
||||
|
||||
class AddressDialog extends Dialog implements ActionListener {
|
||||
private final int BUTTON_WIDTH = 100;
|
||||
private final int BUTTON_HEIGHT = 28;
|
||||
|
||||
private List mSendToList; //ListBox gadget that holds recipients names.
|
||||
private JTable mTable; //Tbale displays the address book entries.
|
||||
private Vector mAddresses; //a parallel list of recipients with mSendToList.
|
||||
private boolean wasCanceled = true; //true if Cancel button was used to dismiss dialog.
|
||||
|
||||
//FIX remove
|
||||
final Object[][] data = {
|
||||
{"Name",
|
||||
"Lester Schueler",
|
||||
"Don Vale",
|
||||
"Chris Dreckman",
|
||||
"Fred Cutler",
|
||||
"Rod Spears"
|
||||
},
|
||||
{"Email Address",
|
||||
"lesters@netscape.com",
|
||||
"dvale@netscape.com",
|
||||
"chrisd@netscape.com",
|
||||
"fredc@netscape.com",
|
||||
"rods@netscape.com"
|
||||
},
|
||||
{"Organization",
|
||||
"Netscape Comm.",
|
||||
"Netscape Comm.",
|
||||
"Netscape Comm.",
|
||||
"Netscape Comm.",
|
||||
"Netscape Comm."
|
||||
},
|
||||
{"Phone",
|
||||
"(619)618-2227",
|
||||
"(619)618-2224",
|
||||
"(619)618-2211",
|
||||
"(619)618-2206",
|
||||
"(619)618-2228"
|
||||
}
|
||||
};
|
||||
|
||||
//FIX remove
|
||||
public static void main(String[] args) {
|
||||
Frame frame = new JFrame();
|
||||
frame.setBackground(Color.lightGray);
|
||||
|
||||
AddressDialog aDialog = new AddressDialog(frame);
|
||||
aDialog.show ();
|
||||
aDialog.dispose();
|
||||
|
||||
frame.show();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
AddressDialog(Frame aParent) {
|
||||
//FIX: Resource
|
||||
super(aParent, "Select Addresses", true);
|
||||
|
||||
mAddresses = new Vector();
|
||||
|
||||
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
|
||||
|
||||
JComponent lookupPanel = createLookupPanel ();
|
||||
add (lookupPanel);
|
||||
|
||||
JComponent SendToPanel = createSendToPanel ();
|
||||
add (SendToPanel);
|
||||
|
||||
JComponent bottomPanel = createBottomPanel ();
|
||||
add (bottomPanel);
|
||||
|
||||
setResizable(false);
|
||||
setSize (716, 480);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private JPanel createLookupPanel () {
|
||||
//the outer most panel has groove etched into it.
|
||||
JPanel outerPanel = new JPanel(true);
|
||||
|
||||
//FIX: Resource
|
||||
outerPanel.setBorder(new TitledBorder(new EtchedBorder(), "Type in the name you are looking for:"));
|
||||
outerPanel.setLayout (new BorderLayout ());
|
||||
outerPanel.setPreferredSize(new Dimension (500, 225));
|
||||
|
||||
// "North" panel
|
||||
JPanel northPanel = new JPanel (true);
|
||||
northPanel.setLayout (new FlowLayout (FlowLayout.LEFT, 5, 5));
|
||||
northPanel.setPreferredSize(new Dimension (500, 35));
|
||||
|
||||
//Search text field
|
||||
JTextField searchTxt = new JTextField (20);
|
||||
northPanel.add (searchTxt);
|
||||
|
||||
//FIX: Resource
|
||||
northPanel.add (new JLabel ("In:"));
|
||||
|
||||
JComboBox combo = new JComboBox();
|
||||
combo.setPreferredSize(new Dimension (275, 25));
|
||||
northPanel.add (combo);
|
||||
|
||||
//FIX: Resource
|
||||
JButton b = makeButton ("Search", BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||
ButtonModel bm = b.getModel();
|
||||
bm.setEnabled(false);
|
||||
northPanel.add (b);
|
||||
|
||||
// Center table
|
||||
TableModel dataModel;
|
||||
|
||||
// Create the table data model
|
||||
dataModel = new AbstractTableModel() {
|
||||
public int getRowCount() { return data[0].length - 1; }
|
||||
|
||||
public int getColumnCount() { return data.length; }
|
||||
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
return data[columnIndex][rowIndex+1];
|
||||
}
|
||||
|
||||
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
||||
data[columnIndex][rowIndex+1] = aValue;
|
||||
}
|
||||
|
||||
public int getColumnIndex(Object aID) {
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
if (data[i][0].equals(aID)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
// Create the table
|
||||
mTable = new JTable(dataModel);
|
||||
|
||||
// Added our columns into the column model
|
||||
for (int columnIndex = 0; columnIndex < data.length; columnIndex++){
|
||||
// Create a column object for each column of data
|
||||
TableColumn newColumn = new TableColumn(columnIndex);
|
||||
|
||||
newColumn.setWidth(200);
|
||||
mTable.addColumn(newColumn);
|
||||
}
|
||||
|
||||
mTable.setColumnSelectionAllowed(false);
|
||||
mTable.setShowGrid(false);
|
||||
|
||||
// Put the table and header into a scrollPane
|
||||
JScrollPane scrollpane = new JScrollPane();
|
||||
JTableHeader tableHeader = mTable.getTableHeader();
|
||||
|
||||
// create and add the column heading to the scrollpane's
|
||||
// column header viewport
|
||||
JViewport headerViewport = new JViewport();
|
||||
headerViewport.setLayout(new BoxLayout(headerViewport, BoxLayout.X_AXIS));
|
||||
headerViewport.add(tableHeader);
|
||||
scrollpane.setColumnHeader(headerViewport);
|
||||
|
||||
// add the table to the viewport
|
||||
JViewport mainViewPort = scrollpane.getViewport();
|
||||
mainViewPort.add(mTable);
|
||||
|
||||
// speed up resizing repaints by turning off live cell updates
|
||||
tableHeader.setUpdateTableInRealTime(false);
|
||||
|
||||
// South panel
|
||||
JPanel southPanel = new JPanel (true);
|
||||
|
||||
//FIX: Resource
|
||||
southPanel.setLayout (new FlowLayout (FlowLayout.LEFT, 10, 0));
|
||||
southPanel.add (makeButton ("To:", BUTTON_WIDTH, BUTTON_HEIGHT));
|
||||
southPanel.add (makeButton ("Cc:", BUTTON_WIDTH, BUTTON_HEIGHT));
|
||||
southPanel.add (makeButton ("Bcc:", BUTTON_WIDTH, BUTTON_HEIGHT));
|
||||
|
||||
//FIX
|
||||
JButton jb = makeButton ("Add to Address Book", 184, BUTTON_HEIGHT);
|
||||
ButtonModel jbm = jb.getModel();
|
||||
jbm.setEnabled(false);
|
||||
southPanel.add (jb);
|
||||
|
||||
JPanel panel2 = new JPanel (new BorderLayout (5, 5), true);
|
||||
panel2.setBorder (new EmptyBorder (5, 5, 5, 5));
|
||||
panel2.add (northPanel, BorderLayout.NORTH);
|
||||
panel2.add (scrollpane, BorderLayout.CENTER);
|
||||
panel2.add (southPanel, BorderLayout.SOUTH);
|
||||
|
||||
outerPanel.add (panel2, BorderLayout.CENTER);
|
||||
return outerPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Send To Panel holds the list people.
|
||||
*/
|
||||
private JPanel createSendToPanel () {
|
||||
//the outer most panel has groove etched into it.
|
||||
JPanel etchedPanel = new JPanel();
|
||||
|
||||
//FIX: Resource
|
||||
etchedPanel.setBorder(new TitledBorder(new EtchedBorder(), "This message will be sent to:"));
|
||||
etchedPanel.setLayout (new BorderLayout (5, 5));
|
||||
etchedPanel.setPreferredSize(new Dimension (500, 175));
|
||||
|
||||
JPanel panel2 = new JPanel (new BorderLayout (5, 5), true);
|
||||
panel2.setBorder (new EmptyBorder(5, 5, 5, 5));
|
||||
|
||||
// Center Listbox panel
|
||||
mSendToList = new List();
|
||||
mSendToList.setBackground (Color.white);
|
||||
panel2.add (mSendToList, BorderLayout.CENTER);
|
||||
|
||||
JPanel panel3 = new JPanel (new BorderLayout(), true);
|
||||
|
||||
//FIX: Resource
|
||||
panel3.add (makeButton ("Remove", BUTTON_WIDTH, BUTTON_HEIGHT), BorderLayout.WEST);
|
||||
panel2.add (panel3, BorderLayout.SOUTH);
|
||||
|
||||
etchedPanel.add (panel2, BorderLayout.CENTER);
|
||||
return etchedPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bottom panel has the ok, cancel and help buttons.
|
||||
*/
|
||||
private JPanel createBottomPanel () {
|
||||
JPanel panel = new JPanel (true);
|
||||
panel.setLayout (new FlowLayout (FlowLayout.CENTER, 25, 8));
|
||||
|
||||
//FIX: Resource
|
||||
panel.add (makeButton ("OK", BUTTON_WIDTH, BUTTON_HEIGHT));
|
||||
panel.add (makeButton ("Cancel", BUTTON_WIDTH, BUTTON_HEIGHT));
|
||||
|
||||
//FIX
|
||||
JButton b = makeButton ("Help", BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||
panel.add (b);
|
||||
ButtonModel bm = b.getModel();
|
||||
bm.setEnabled(false);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
private JButton makeButton (String aLabel, int aWidth, int aHeight) {
|
||||
JButton button = new JButton (aLabel);
|
||||
button.setPreferredSize(new Dimension (aWidth, aHeight));
|
||||
button.addActionListener (this);
|
||||
return button;
|
||||
}
|
||||
|
||||
public Insets getInsets () {
|
||||
return (new Insets (25, 10, 10, 10));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entry to the send list.
|
||||
* @param The Addressee to be added to the list.
|
||||
*/
|
||||
private void addToSendList (Addressee aAddressee) {
|
||||
if (null != aAddressee) {
|
||||
mSendToList.add (aAddressee.deliveryString () + " " + aAddressee.getText());
|
||||
mAddresses.addElement (aAddressee);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified entry from the list.
|
||||
* @param The index of the entry to remove.
|
||||
*/
|
||||
private void removeFromSendList (int aIndex) {
|
||||
if (-1 < aIndex) {
|
||||
mSendToList.remove (aIndex);
|
||||
mAddresses.removeElementAt (aIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the address from aa Array.
|
||||
* @param aAddresses An array of addresses.
|
||||
* @see getAddresses
|
||||
*/
|
||||
public void setAddresses (Addressee[] aAddresses) {
|
||||
mAddresses.removeAllElements();
|
||||
mSendToList.removeAll();
|
||||
|
||||
if (null != aAddresses) {
|
||||
for (int i = 0; i < aAddresses.length; i++) {
|
||||
addToSendList (aAddresses[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the addresses in the form of an array.
|
||||
* @returns An array of addresses.
|
||||
* @see setAddresses
|
||||
*/
|
||||
public Addressee[] getAddresses () {
|
||||
int arrSize = mAddresses.size();
|
||||
|
||||
if (0 < arrSize) {
|
||||
Addressee[] anArray = new Addressee[arrSize];
|
||||
mAddresses.copyInto(anArray);
|
||||
return anArray;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if cancel was pressed.
|
||||
*/
|
||||
public boolean getCanceled () { return wasCanceled; }
|
||||
|
||||
/**
|
||||
* Actions to respond to are button pressed for "To", "Cc", "Bcc", "Ok", and "Canel"
|
||||
*/
|
||||
public void actionPerformed (ActionEvent e) {
|
||||
String s = e.getActionCommand ();
|
||||
|
||||
//FIX: Resource
|
||||
if (s.equals ("To:")) {
|
||||
int selectedRow = mTable.getSelectedRow();
|
||||
if (-1 != selectedRow)
|
||||
addToSendList (new Addressee ((String) data[1][selectedRow + 1], Addressee.TO));
|
||||
}
|
||||
//FIX: Resource
|
||||
else if (s.equals ("Cc:")) {
|
||||
int selectedRow = mTable.getSelectedRow();
|
||||
if (-1 != selectedRow)
|
||||
addToSendList (new Addressee ((String) data[1][selectedRow + 1], Addressee.CC));
|
||||
}
|
||||
//FIX: Resource
|
||||
else if (s.equals ("Bcc:")) {
|
||||
int selectedRow = mTable.getSelectedRow();
|
||||
if (-1 != selectedRow)
|
||||
addToSendList (new Addressee ((String) data[1][selectedRow + 1], Addressee.BCC));
|
||||
}
|
||||
//FIX: Resource
|
||||
else if (s.equals ("Remove")) {
|
||||
int index = mSendToList.getSelectedIndex();
|
||||
|
||||
if (-1 < index)
|
||||
removeFromSendList (index);
|
||||
}
|
||||
//FIX: Resource
|
||||
else if (s.equals ("Cancel")) {
|
||||
wasCanceled = true;
|
||||
setVisible(false);
|
||||
}
|
||||
//FIX: Resource
|
||||
else if (s.equals ("OK")) {
|
||||
wasCanceled = false;
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче