This commit is contained in:
jwz%mozilla.org 1998-09-09 00:52:38 +00:00
Родитель 12d97f5341
Коммит a7d6d7afa6
554 изменённых файлов: 67063 добавлений и 0 удалений

49
grendel/Main.java Normal file
Просмотреть файл

@ -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();
}
}

55
grendel/Makefile Normal file
Просмотреть файл

@ -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)

5
grendel/README Normal file
Просмотреть файл

@ -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.

245
grendel/SelfTest.java Normal file
Просмотреть файл

@ -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;
}
}

23
grendel/calypso/Makefile Normal file
Просмотреть файл

@ -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

7
grendel/calypso/README Normal file
Просмотреть файл

@ -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>&nbsp;&nbsp;</TT><I>... write bytes to `output' ...</I><BR>
<TT>&nbsp;&nbsp;output.close();</TT><BR>
<BR>
<TT>&nbsp;&nbsp;InputStream input = output.makeInputStream();</TT><BR>
<TT>&nbsp;&nbsp;try {</TT><BR>
<TT>&nbsp;&nbsp;&nbsp;&nbsp;</TT><I>... read bytes from `input' ...</I>
<BR>
<TT>&nbsp;&nbsp;} finally {</TT><BR>
<TT>&nbsp;&nbsp;&nbsp;&nbsp;input.close();</TT><BR>
<TT>&nbsp;&nbsp;}</TT><BR>
<BR>
<TT>} finally {</TT><BR>
<TT>&nbsp;&nbsp;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);
}
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше