xmpp connection blackberry java - java

Im able to connect with xmpp server and login authentication is done but when im sending roster the inputstream is.read() giving me -1 and thrown an exception i dont know what to do now.please help me out.
My XMppCOnnection class:
package mypackage;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Vector;
import javax.microedition.io.ConnectionNotFoundException
import javax.microedition.io.SecureConnection;
import javax.microedition.io.StreamConnection;
import net.rim.device.api.io.File;
import net.rim.device.api.io.FileInputStream;
import net.rim.device.api.io.FileOutputStream;
public class XMPPConnection extends XMPPThread {
private XmlReader reader;
private XmlWriter writer;
private InputStream is;
private OutputStream os;
FileInputStream fis;
FileOutputStream fos;
File file;
/**
* If you create this object all variables will be saved and the
* method {#link #run()} is started to log in on jabber server and
* listen to parse incomming xml stanzas. Use
* {#link #addListener(XmppListener xl)} to listen to events of this object.
*/
// jid must in the form "username#host"
// to login Google Talk, set port to 5223 (NOT 5222 in their offical guide)
public XMPPConnection(Connection connection) {
super(connection);
this.host = connection.getHost();
this.port = connection.getPort();
this.username = connection.getUsername();
this.password = connection.getPassword();
this.resource = "mobile";
this.myjid = this.username + "#" + this.host;
if (connection.getServer() == null)
this.server = host;
else
this.server = connection.getServer();
this.use_ssl = connection.isSSL();
this.connectionMaskIndex = connection.getNetworkType();
}
/**
* The <code>run</code> method is called when {#link XMPPConnection} object is
* created. It sets up the reader and writer, calls {#link #login()}
* methode and listens on the reader to parse incomming xml stanzas.
*/
public void run() {
try {
this.connect();
} catch (final IOException e) {
e.printStackTrace();
this.connectionFailed(e.getMessage());
return;
} catch (Exception e) {
e.printStackTrace();
this.connectionFailed(e.getMessage());
return;
}
// connected
try {
boolean loginSuccess = this.login();
if (loginSuccess) {
this.parse();
}
} catch (final Exception e) {
// hier entsteht der connection failed bug (Network Down)
java.lang.System.out.println(e);
this.connectionFailed(e.toString());
}
}
protected void connect() throws IOException, Exception {
if (!use_ssl) {
//final StreamConnection connection = (StreamConnection) Connector.open("http://" + this.server + ":" + this.port+this.connectionMask, Connector.READ_WRITE);
ConnectionFactory connectionFactory = new ConnectionFactory("socket://" + this.server + ":" + this.port, this.connectionMaskIndex);
StreamConnection connection = null;
try {
connection = (StreamConnection) connectionFactory.getNextConnection();
} catch (NoMoreTransportsException e) {
throw new Exception("Connection failed. No transport available.");
} catch (ConnectionNotFoundException e) {
throw new Exception("ConnectionNotFoundException:" + e.getMessage());
} catch (IllegalArgumentException e) {
throw new Exception("IllegalArgumentException: " + e.getMessage());
} catch (IOException e) {
throw new Exception("IOException: " + e.getMessage());
}
is = connection.openInputStream();
os = connection.openOutputStream();
this.reader = new XmlReader(is);
this.writer = new XmlWriter(os);
} else {
//final SecureConnection sc = (SecureConnection) Connector.open("ssl://" + this.server + ":" + this.port+this.connectionMask, Connector.READ_WRITE);
ConnectionFactory connectionFactory = new ConnectionFactory("ssl://" + this.server + ":" + this.port, this.connectionMaskIndex);
SecureConnection sc = null;
try {
sc = (SecureConnection) connectionFactory.getNextConnection();
} catch (NoMoreTransportsException e) {
throw new Exception("Connection failed. No transport available.");
} catch (ConnectionNotFoundException e) {
throw new Exception("ConnectionNotFoundException: " + e.getMessage());
} catch (IllegalArgumentException e) {
throw new Exception("IllegalArgumentException: " + e.getMessage());
} catch (IOException e) {
throw new Exception("IOException: " + e.getMessage());
}
if (sc != null) {
//sc.setSocketOption(SocketConnection.DELAY, 1);
//sc.setSocketOption(SocketConnection.LINGER, 0);
is = sc.openInputStream();
os = sc.openOutputStream();
this.reader = new XmlReader(is);
this.writer = new XmlWriter(os);
}
}
}
/**
* Opens the connection with a stream-tag, queries authentication type and
* sends authentication data, which is username, password and resource.
* #return
* #throws Exception
*/
protected boolean login() throws Exception {
String msg = "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='" + this.host + "' version='1.0'>";
os.write(msg.getBytes());
os.flush();
do {
reader.next();
if (reader.getType() == XmlReader.START_TAG && reader.getName().equals("stream:features")) {
this.packetParser.parseFeatures(reader);
}
} while (!(reader.getType() == XmlReader.END_TAG && reader.getName().equals("stream:features")));
boolean loginSuccess = this.doAuthentication();
msg = "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='" + this.host + "' version='1.0'>";
os.write(msg.getBytes());
os.flush();
reader.next();
while (true) {
if ((reader.getType() == XmlReader.END_TAG) && reader.getName().equals("stream:features")) {
break;
}
reader.next();
}
if (resource == null) {
msg = "<iq type='set' id='res_binding'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></iq>";
} else {
msg = "<iq type='set' id='res_binding'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><resource>" + resource + "</resource></bind></iq>";
}
os.write(msg.getBytes());
os.flush();
return loginSuccess;
}
protected void parse() throws IOException {
while (true) {
int nextTag = this.reader.next();
switch (nextTag) {
case XmlReader.START_TAG:
final String tmp = this.reader.getName();
if (tmp.equals("message")) {
this.packetParser.parseMessage(this.reader);
} else if (tmp.equals("presence")) {
this.packetParser.parsePresence(this.reader);
} else if (tmp.equals("iq")) {
this.packetParser.parseIq(this.reader, this.writer);
} else {
this.packetParser.parseIgnore(this.reader);
}
break;
case XmlReader.END_TAG:
this.reader.close();
throw new IOException("Unexpected END_TAG "+this.reader.getName());
default:
this.reader.close();
throw new IOException("Bad XML tag");
}
}
}
protected boolean doAuthentication() throws Exception {
boolean loginSuccess = false;
Vector mechanismList = this.packetParser.getMechanism();
System.out.println(mechanismList.toString());
if (mechanismList.contains("X-GOOGLE-TOKEN")) {
// X-GOOGLE-TOKEN authorization doing. User can disable
// google features using by deselecting corresponding
// checkbox in profile
String resp = this.packetParser.getGoogleToken(this.myjid, this.password);
String msg = "<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"X-GOOGLE-TOKEN\">" + resp + "</auth>";
os.write(msg.getBytes());
//os.flush();
reader.next();
if (reader.getName().equals("success")) {
loginSuccess = true;
while (true) {
if ((reader.getType() == XmlReader.END_TAG) && reader.getName().equals("success")) {
break;
}
reader.next();
}
}
}
if (mechanismList.contains("PLAIN") && loginSuccess == false) {
String msg = "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>";
byte[] auth_msg = (username + "#" + host + "\0" + username + "\0" + password).getBytes();
msg = msg + MD5.toBase64(auth_msg) + "</auth>";
os.write(msg.getBytes());
os.flush();
reader.next();
if (reader.getName().equals("success")) {
loginSuccess = true;
while (true) {
if ((reader.getType() == XmlReader.END_TAG) && reader.getName().equals("success")) {
break;
}
reader.next();
}
}
}
if (loginSuccess == false) {
for (Enumeration e = listeners.elements(); e.hasMoreElements();) {
XmppListener xl = (XmppListener) e.nextElement();
xl.onAuthFailed(reader.getName() + ", failed authentication");
}
return false;
}
return loginSuccess;
}
public void getRosterVCard(String tojid) throws IOException {
this.writer.startTag("iq");
this.writer.attribute("id", "vc2");
this.writer.attribute("to", tojid);
this.writer.attribute("type", "get");
this.writer.startTag("vCard");
this.writer.attribute("xmlns", "vcard-temp");
this.writer.endTag(); // vCard
this.writer.endTag(); // iq
this.writer.flush();
}
/**
* Sends a roster query.
*
* #throws java.io.IOException is thrown if {#link XmlReader} or {#link XmlWriter}
* throw an IOException.
*/
public void getRoster() throws IOException {
this.writer.startTag("iq");
// this.writer.attribute("id", "roster");
this.writer.attribute("type", "get");
this.writer.startTag("query");
this.writer.attribute("xmlns", "jabber:iq:roster");
this.writer.endTag(); // query
this.writer.endTag(); // iq
this.writer.flush();
//<iq id="qxmpp7" from="919700424402#213.204.83.20/QXmpp" type="get"><query xmlns="jabber:iq:roster"/></iq>
}
/**
* Sends a message text to a known jid.
*
* #param to the JID of the recipient
* #param msg the message itself
*/
public void sendMessage(final String to, final String msg, final String id) {
try {
this.writer.startTag("message");
this.writer.attribute("type", "chat");
this.writer.attribute("to", to);
this.writer.startTag("body");
this.writer.text(msg);
this.writer.endTag();
this.writer.endTag();
this.writer.flush();
} catch (final IOException e) {
java.lang.System.out.println(e);
this.connectionFailed();
}
}
/**
* Requesting a subscription.
*
* #param to the jid you want to subscribe
*/
public void subscribe(final String to) {
this.sendPresence(to, "subscribe", null, null, 0);
}
/**
* Remove a subscription.
*
* #param to the jid you want to remove your subscription
*/
public void unsubscribe(final String to) {
this.sendPresence(to, "unsubscribe", null, null, 0);
}
/**
* Approve a subscription request.
*
* #param to the jid that sent you a subscription request
*/
public void subscribed(final String to) {
this.sendPresence(to, "subscribed", null, null, 0);
}
/**
* Refuse/Reject a subscription request.
*
* #param to the jid that sent you a subscription request
*/
public void unsubscribed(final String to) {
this.sendPresence(to, "unsubscribed", null, null, 0);
}
/**
* Sets your Jabber Status.
*
* #param show is one of the following: <code>null</code>, chat, away,
* dnd, xa, invisible
* #param status an extended text describing the actual status
* #param priority the priority number (5 should be default)
*/
public void setStatus(String show, String status, final int priority) {
if (show.equals("")) {
show = null;
}
if (status.equals("")) {
status = null;
}
if (show.equals("invisible")) {
this.sendPresence(null, "invisible", null, null, priority);
} else {
this.sendPresence(null, null, show, status, priority);
}
}
/**
* Sends a presence stanza to a jid. This method can do various task but
* it's private, please use setStatus to set your status or explicit
* subscription methods subscribe, unsubscribe, subscribed and
* unsubscribed to change subscriptions.
*/
public void sendPresence(final String to, final String type, final String show, final String status, final int priority) {
try {
this.writer.startTag("presence");
if (type != null) {
this.writer.attribute("type", type);
}
if (to != null) {
this.writer.attribute("to", to);
}
if (show != null) {
this.writer.startTag("show");
this.writer.text(show);
this.writer.endTag();
}
if (status != null) {
this.writer.startTag("status");
this.writer.text(status);
this.writer.endTag();
}
if (priority != 0) {
this.writer.startTag("priority");
this.writer.text(Integer.toString(priority));
this.writer.endTag();
}
this.writer.endTag(); // presence
this.writer.flush();
} catch (final IOException e) {
java.lang.System.out.println(e);
this.connectionFailed();
}
}
/**
* Closes the stream-tag and the {#link XmlWriter}.
*/
public void logoff() {
try {
this.writer.endTag();
this.writer.flush();
this.writer.close();
} catch (final IOException e) {
java.lang.System.out.println(e);
this.connectionFailed();
}
}
/**
* Save a contact to roster. This means, a message is send to jabber
* server (which hosts your roster) to update the roster.
*
* #param jid the jid of the contact
* #param name the nickname of the contact
* #param group the group of the contact
* #param subscription the subscription of the contact
*/
public void saveContact(final String jid, final String name, final Enumeration group, final String subscription) {
try {
this.writer.startTag("iq");
this.writer.attribute("type", "set");
this.writer.startTag("query");
this.writer.attribute("xmlns", "jabber:iq:roster");
this.writer.startTag("item");
this.writer.attribute("jid", jid);
if (name != null) {
this.writer.attribute("name", name);
}
if (subscription != null) {
this.writer.attribute("subscription", subscription);
}
if (group != null) {
while (group.hasMoreElements()) {
this.writer.startTag("group");
this.writer.text((String) group.nextElement());
this.writer.endTag(); // group
}
}
this.writer.endTag(); // item
this.writer.endTag(); // query
this.writer.endTag(); // iq
this.writer.flush();
} catch (final IOException e) {
java.lang.System.out.println(e);
this.connectionFailed();
}
}
/**
* This method is used to be called on a parser or a connection error.
* It tries to close the XML-Reader and XML-Writer one last time.
*
*/
private void connectionFailed() {
if (this.writer != null)
this.writer.close();
if (this.reader != null)
this.reader.close();
for (Enumeration e = listeners.elements(); e.hasMoreElements();) {
XmppListener xl = (XmppListener) e.nextElement();
xl.onConnFailed("");
}
}
private void connectionFailed(final String msg) {
if (this.writer != null)
this.writer.close();
if (this.reader != null)
this.reader.close();
for (Enumeration e = listeners.elements(); e.hasMoreElements();) {
XmppListener xl = (XmppListener) e.nextElement();
xl.onConnFailed(msg);
}
}
};
xml reader looks like this:
public class XmlReader {
private InputStream is;
public final static int START_DOCUMENT = 0;
public final static int END_DOCUMENT = 1;
public final static int START_TAG = 2;
public final static int END_TAG = 3;
public final static int TEXT = 4;
//private Stack tags;
private boolean inside_tag;
private boolean left_angle;
private String tagName;
private String text;
private final Hashtable attributes = new Hashtable();
private int c;
private int type = START_DOCUMENT;
//public XmlReader(final InputStream in) throws IOException, UnsupportedEncodingException {
public XmlReader(final InputStream in) throws IOException {
//reader = new InputStreamReader(in, "UTF-8");
this.is = in;
//this.tags = new Stack();
this.inside_tag = false;
this.left_angle = false;
}
//http://discussion.forum.nokia.com/forum/showthread.php?t=76814
//by abirr
private int getNextCharacter() throws IOException {
int a = is.read();
int t=a;
if((t|0xC0)==t){
int b = is.read();
if( b == 0xFF ){ // Check if legal
t=-1;
}else if( b < 0x80 ){ // Check for UTF8 compliancy
throw new IOException("Bad UTF-8 Encoding encountered");
}else if((t|0xE0)==t) {
int c = is.read();
if( c == 0xFF ){ // Check if legal
t=-1;
}else if( c < 0x80 ){ // Check for UTF8 compliancy
throw new IOException("Bad UTF-8 Encoding encountered");
}else
t=((a & 0x0F)<<12) | ((b & 0x3F)<<6) | (c & 0x3F);
}else
t=((a & 0x1F)<<6)|(b&0x3F);
}
return a;
}
public void close() {
if (is != null) {
try {
is.close();
is = null;
} catch (IOException e) {
e.printStackTrace();
}
/*try {
reader.close();
} catch (IOException e) {}*/
}
}
public int next() throws IOException {
/* while (!this.ready())
try {
java.lang.Thread.sleep(100);
} catch (InterruptedException e) {}*/
this.c = getNextCharacter();
if (this.c <= ' ') {
while (((this.c = getNextCharacter()) <= ' ') && (this.c != -1)) {
;
}
}
if (this.c == -1) {
this.type = END_DOCUMENT;
return this.type;
}
if (this.left_angle || (this.c == '<')) {
this.inside_tag = true;
// reset all
this.tagName = null;
this.text = null;
this.attributes.clear();
if (this.c == '<') {
this.left_angle = true;
this.c = getNextCharacter();
}
if (this.left_angle && this.c == '/') {
this.left_angle = false;
this.type = END_TAG;
this.c = getNextCharacter();
this.tagName = this.readName('>');
} else if (this.left_angle && ((this.c == '?') || (this.c == '!'))) {// ignore xml heading & // comments
this.left_angle = false;
while ((this.c = getNextCharacter()) != '>') {
;
}
this.next();
} else {
this.left_angle = false;
this.type = START_TAG;
this.tagName = this.readName(' ');
String attribute = "";
String value = "";
while (this.c == ' ') {
/*this.c = getNextCharacter();
attribute = this.readName('=');
int quote = getNextCharacter();//this.c = this.read(); // '''
BTalk.debugConsole.addDebugMsg("quote: " + quote);
this.c = getNextCharacter();
value = this.readText(quote); //change from value = this.readText(''');
this.c = getNextCharacter();
this.attributes.put(attribute, value);
BTalk.debugConsole.addDebugMsg("attributes: " + attributes);*/
this.c = getNextCharacter();
attribute = this.readName('=').trim();
int quote = getNextCharacter();//this.c = this.read(); // '''
if (quote == 32) {
while (quote == 32) {
quote = getNextCharacter();//this.c = this.read(); // '''
}
this.c = getNextCharacter();
value = this.readText(quote); //change from value = this.readText(''');
this.c = getNextCharacter();
this.attributes.put(attribute, value);
} else {
this.c = getNextCharacter();
value = this.readText(quote); //change from value = this.readText(''');
this.c = getNextCharacter();
this.attributes.put(attribute, value);
}
}
if (this.c != '/') {
this.inside_tag = false;
}
}
} else if ((this.c == '>') && this.inside_tag) // last tag ended
{
this.type = END_TAG;
this.inside_tag = false;
} else {
this.tagName = null;
this.attributes.clear();
this.type = TEXT;
this.text = this.readText('<');
// fix the < dismatching problem
this.left_angle = true;
}
return this.type;
}
// NOTICE: this is only for debug use
public void parseHtml() throws IOException {
while (true) {
char c;
c = (char) this.getNextCharacter();
System.out.print(c);
}
}
public int getType() {
return this.type;
}
public String getName() {
return this.tagName;
}
public String getAttribute(final String name) {
return (String) this.attributes.get(name);
}
public Enumeration getAttributes() {
return this.attributes.keys();
}
public String getText() {
return this.text;
}
private String readText(final int end) throws IOException {
final StringBuffer output = new StringBuffer("");
while (this.c != end) {
if (this.c == '&') {
this.c = getNextCharacter();
switch (this.c) {
case 'l':
output.append('<');
break;
case 'g':
output.append('>');
break;
case 'a':
if (getNextCharacter() == 'm') {
output.append('&');
} else {
output.append('\'');
}
break;
case 'q':
output.append('"');
break;
case 'n':
output.append(' ');
break;
default:
output.append('?');
}
while ((this.c = getNextCharacter()) != ';') {
;
}
// NOTICE: Comment out these mystical codes
// } else if (this.c == '\\') {
// // NOTICE: What this means?
// if ((this.c = getNextCharacter()) == '<') {
// output.append('\\');
// break;
// } else {
// output.append((char) this.c);
// }
} else {
output.append((char) this.c);
}
this.c = getNextCharacter();
}
// while((c = read()) != end);
System.out.println(output.toString()+"");
return output.toString();
}
private String readName(final int end) throws IOException {
final StringBuffer output = new StringBuffer("");
do {
output.append((char) this.c);
} while (((this.c = getNextCharacter()) != end) && (this.c != '>') && (this.c != '/'));
return output.toString();
}
};

the problem is with session we need to create session before roster
String msg = "<iq type=\"set\" id=\"session_1\"><session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/></iq>";
try {
os.write(msg.getBytes());
os.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
reader.next();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (reader.getName().equals("iq")) {
while (true) {
if((reader.getType() == XmlReader.END_TAG) && reader.getName().equals("iq"))
{
session=true;
break;
}
try {
reader.next();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//
now the problem is solved.thank you

Related

how to make this sql file runner to write logs to a file

i want the below program to write the logs to a file ,its printing both errors and info but same needs to be captured into a file.can any one suggest the chnages .
i tried using buffer writer but dint succeed.
/**
* Tool to run database scripts
*/
/*BufferedWriter bw = null;
String path = "logs/sql.log";
try {
bw = new BufferedWriter(new FileWriter(new File(path)));
}*/
public class ScriptRunner {
private static final String DEFAULT_DELIMITER = ";";
private Connection connection;
private boolean stopOnError;
private boolean autoCommit;
private PrintWriter logWriter = new PrintWriter(System.out);
private PrintWriter errorLogWriter = new PrintWriter(System.err);
private String delimiter = DEFAULT_DELIMITER;
private boolean fullLineDelimiter = false;
private static final String DELIMITER_LINE_REGEX = "(?i)DELIMITER.+";
private static final String DELIMITER_LINE_SPLIT_REGEX = "(?i)DELIMITER";
/**
* Default constructor
*/
public ScriptRunner(Connection connection, boolean autoCommit,
boolean stopOnError) {
this.connection = connection;
this.autoCommit = autoCommit;
this.stopOnError = stopOnError;
}
public void setDelimiter(String delimiter, boolean fullLineDelimiter) {
this.delimiter = delimiter;
this.fullLineDelimiter = fullLineDelimiter;
}
/**
* Setter for logWriter property
*
* #param logWriter
* - the new value of the logWriter property
* #throws IOException
*/
public void setLogWriter(PrintWriter logWriter) throws IOException {
this.logWriter = logWriter;
}
/**
* Setter for errorLogWriter property
*
* #param errorLogWriter
* - the new value of the errorLogWriter property
*/
public void setErrorLogWriter(PrintWriter errorLogWriter) {
this.errorLogWriter = errorLogWriter;
}
/**
* Runs an SQL script (read in using the Reader parameter)
*
* #param reader
* - the source of the script
*/
public void runScript(Reader reader) throws IOException, SQLException {
try {
boolean originalAutoCommit = connection.getAutoCommit();
try {
if (originalAutoCommit != this.autoCommit) {
connection.setAutoCommit(this.autoCommit);
}
runScript(connection, reader);
} finally {
connection.setAutoCommit(originalAutoCommit);
}
} catch (IOException e) {
throw e;
} catch (SQLException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("Error running script. Cause: " + e, e);
}
}
/**
* Runs an SQL script (read in using the Reader parameter) using the
* connection passed in
*
* #param conn
* - the connection to use for the script
* #param reader
* - the source of the script
* #throws SQLException
* if any SQL errors occur
* #throws IOException
* if there is an error reading from the Reader
*/
private void runScript(Connection conn, Reader reader) throws IOException,
SQLException {
StringBuffer command = null;
try {
LineNumberReader lineReader = new LineNumberReader(reader);
String line = null;
while ((line = lineReader.readLine()) != null) {
if (command == null) {
command = new StringBuffer();
}
String trimmedLine = line.trim();
if (trimmedLine.startsWith("--")) {
println(trimmedLine);
} else if (trimmedLine.length() < 1
|| trimmedLine.startsWith("//")) {
// Do nothing
} else if (trimmedLine.length() < 1
|| trimmedLine.startsWith("--")) {
// Do nothing
} else if (!fullLineDelimiter
&& trimmedLine.endsWith(getDelimiter())
|| fullLineDelimiter
&& trimmedLine.equals(getDelimiter())) {
Pattern pattern = Pattern.compile(DELIMITER_LINE_REGEX);
Matcher matcher = pattern.matcher(trimmedLine);
if (matcher.matches()) {
setDelimiter(trimmedLine.split(DELIMITER_LINE_SPLIT_REGEX)[1].trim(), fullLineDelimiter);
line = lineReader.readLine();
if (line == null) {
break;
}
trimmedLine = line.trim();
}
command.append(line.substring(0, line.lastIndexOf(getDelimiter())));
command.append(" ");
Statement statement = conn.createStatement();
println(command);
boolean hasResults = false;
if (stopOnError) {
hasResults = statement.execute(command.toString());
} else {
try {
statement.execute(command.toString());
} catch (SQLException e) {
e.fillInStackTrace();
printlnError("Error executing: " + command);
printlnError(e);
}
}
if (autoCommit && !conn.getAutoCommit()) {
conn.commit();
}
ResultSet rs = statement.getResultSet();
if (hasResults && rs != null) {
ResultSetMetaData md = rs.getMetaData();
int cols = md.getColumnCount();
for (int i = 0; i < cols; i++) {
String name = md.getColumnLabel(i);
print(name + "\t");
}
println("");
while (rs.next()) {
for (int i = 0; i < cols; i++) {
String value = rs.getString(i);
print(value + "\t");
}
println("");
}
}
command = null;
try {
statement.close();
} catch (Exception e) {
e.printStackTrace();
// Ignore to workaround a bug in Jakarta DBCP
}
Thread.yield();
} else {
Pattern pattern = Pattern.compile(DELIMITER_LINE_REGEX);
Matcher matcher = pattern.matcher(trimmedLine);
if (matcher.matches()) {
setDelimiter(trimmedLine.split(DELIMITER_LINE_SPLIT_REGEX)[1].trim(), fullLineDelimiter);
line = lineReader.readLine();
if (line == null) {
break;
}
trimmedLine = line.trim();
}
command.append(line);
command.append(" ");
}
}
if (!autoCommit) {
conn.commit();
}
} catch (SQLException e) {
e.fillInStackTrace();
printlnError("Error executing: " + command);
printlnError(e);
throw e;
} catch (IOException e) {
e.fillInStackTrace();
printlnError("Error executing: " + command);
printlnError(e);
throw e;
} finally {
conn.rollback();
flush();
}
}
private String getDelimiter() {
return delimiter;
}
private void print(Object o) {
if (logWriter != null) {
System.out.print(o);
// bw.write("logs/sql.log");
// bw.flush();
}
}
private void println(Object o) {
if (logWriter != null) {
logWriter.println(o);
}
}
private void printlnError(Object o) {
if (errorLogWriter != null) {
errorLogWriter.println(o);
}
}
private void flush() {
if (logWriter != null) {
logWriter.flush();
}
if (errorLogWriter != null) {
errorLogWriter.flush();
}
}
}

ADF Faces: It's possible to Customize Error Handling without ADF BC

Is there away to customize Error Handling in ADF Faces without ADF BC?
This is my approach.
Class MyErrorHandler extends DCErrorHandlerImpl
public class MyErrorHandler extends DCErrorHandlerImpl {
private static final ADFLogger logger = ADFLogger.createADFLogger(MyErrorHandler.class);
private static ResourceBundle rb =
ResourceBundle.getBundle("error.handling.messages.ErrorMessages_de_DE");
public MyErrorHandler() {
super(true);
}
public MyErrorHandler(boolean setToThrow) {
super(setToThrow);
}
public void reportException(DCBindingContainer bc, java.lang.Exception ex) {
disableAppendCodes(ex);
logger.info("entering reportException() method");
BindingContext ctx = bc.getBindingContext();
if (ex instanceof NullPointerException) {
logger.severe(ex);
JboException e = new JboException(rb.getString("STANDARD_ERROR_MESSAGE"));
super.reportException(bc, e);
} else if (ex instanceof RowValException) {
Object[] exceptions = ((RowValException) ex).getDetails();
if (exceptions != null) {
for (int i = 0; i < exceptions.length; i++) {
if (exceptions[i] instanceof RowValException) {
this.reportException(bc, (Exception) exceptions[i]);
} else if (exceptions[i] instanceof AttrValException) {
super.reportException(bc, (Exception) exceptions[i]);
}
}
} else {
this.reportException(bc, ex);
}
} else if (ex instanceof TxnValException) {
Object[] exceptions = ((TxnValException) ex).getDetails();
if (exceptions != null) {
for (int i = 0; i < exceptions.length; i++) {
if (exceptions[i] instanceof RowValException) {
this.reportException(bc, (Exception) exceptions[i]);
} else {
super.reportException(bc, (Exception) exceptions[i]);
}
}
} else {
super.reportException(bc, ex);
}
}
else if (ex instanceof oracle.jbo.DMLException) {
JboException e = new JboException(rb.getString("STANDARD_ERROR_MESSAGE"));
super.reportException(bc, e);
} else if (ex instanceof javax.xml.ws.WebServiceException) {
JboException e = new JboException(rb.getString("WEB_SERVICE_EXCEPTION"));
super.reportException(bc, e);
}
else if (ex instanceof JboException) {
super.reportException(bc, ex);
}
}
public static FacesMessage getMessageFromBundle(String key, FacesMessage.Severity severity) {
ResourceBundle bundle =
ResourceBundle.getBundle("sahaj.apps.vleadministration.view.resources.VLEAdministrationUIBundle");
String summary = JSFUtils.getStringSafely(bundle, key, null);
String detail = JSFUtils.getStringSafely(bundle, key + "_detail", summary);
FacesMessage message = new FacesMessage(summary, detail);
message.setSeverity(severity);
return message;
}
private void disableAppendCodes(Exception ex) {
if (ex instanceof JboException) {
JboException jboEx = (JboException) ex;
jboEx.setAppendCodes(false);
Object[] detailExceptions = jboEx.getDetails();
if ((detailExceptions != null) && (detailExceptions.length > 0)) {
for (int z = 0, numEx = detailExceptions.length; z < numEx; z++) {
System.err.println("Detailed Exception : "+ detailExceptions[z].toString());
disableAppendCodes((Exception) detailExceptions[z]);
}
}
}
}
#Override
protected boolean skipException(Exception ex) {
if (ex instanceof JboException) {
return false;
} else if (ex instanceof SQLIntegrityConstraintViolationException) {
return true;
}
return super.skipException(ex);
}
private String handleApplicationError(String errorMessageRaw) {
String errorMessageCode = getErrorCode(errorMessageRaw);
// application error code
String errorMessage = null;
for (String key : errorPrefixes) {
if (errorMessageCode.startsWith(key)) {
try {
errorMessage = rb.getString(errorMessageCode);
} catch (MissingResourceException mre) {
// application error code not found in the bundle,
// use original message
return errorMessageRaw;
}
break;
}
}
// return the formated application error message
return errorMessage;
}
private String getErrorCode(String errorMessageRaw) {
// check for null/empty error message
if (errorMessageRaw == null || errorMessageRaw.isEmpty()) {
return errorMessageRaw;
}
int start = 0;
String currentErrorCodePrefix = null;
int count = 0;
// check for error message
for (String errorCode : errorPrefixes) {
count += 1;
start = errorMessageRaw.indexOf(errorCode);
if (start >= 0) {
currentErrorCodePrefix = errorCode;
start += currentErrorCodePrefix.length();
break;
}
if (count == errorPrefixes.size())
return errorMessageRaw;
}
int endIndex = start + 5;
// get the CURRENT error code
return currentErrorCodePrefix + errorMessageRaw.substring(start, endIndex);
}
#Override
public String getDisplayMessage(BindingContext bindingContext, Exception exception) {
String data=super.getDisplayMessage(bindingContext, exception);
System.err.println("Exception DATA : "+ data);
String msg= handleApplicationError(data);
System.err.println("Exception MSG : "+ msg);
return msg;
}
#Override
public DCErrorMessage getDetailedDisplayMessage(BindingContext bindingContext, RegionBinding regionBinding,
Exception exception) {
return super.getDetailedDisplayMessage(bindingContext, regionBinding, exception);
}
private static Set<String> errorPrefixes = new HashSet<String>();
static {
errorPrefixes.add("JBO-");
errorPrefixes.add("ORA-");
errorPrefixes.add("DCA-");
}
}
In my DataBinding.cpx
<Application xmlns="http://xmlns.oracle.com/adfm/application" version="12.1.2.66.68" id="DataBindings"
SeparateXMLFiles="false" Package="de.nkk.oasis.ui.web" ClientType="Generic"
ErrorHandlerClass="MyErrorHandler">
After that i generate Data Controller from Myclass.
//MyClass
/**
* method throwing a Nullpointer exception
*/
public void throwNPE() {
Object o = null;
String s = o.toString();
//bang occurs in the line above, no need for any more code
//...
}
/**
* Method that throws a single JboException
*/
public void throwJboException(){
throw new JboException("This is a JboException thrown in ADF BC");
}
and bind the two methods to JSF
<af:button actionListener="#{bindings.throwNPE.execute}" text="throwNPE"
disabled="#{!bindings.throwNPE.enabled}" id="b2"/>
<af:button actionListener="#{bindings.throwJboException.execute}" text="throwJboException"
disabled="#{!bindings.throwJboException.enabled}" id="b3"/>
NOW COMES MY PROBLEM:
Whenever i click one the Button i get
DCA-29000 unexcepted Exception
Try remove
disabled="#{!bindings.throwNPE.enabled}"
and
disabled="#{!bindings.throwJboException.enabled}"

java.io.StreamCorruptedException: invalid type code: 4C - replicationstream tomcat

I have following code
The function writes objects to the replicationstream provided by tomcat. IF the object is not serializable then I am trying to write "Misssing value".
public void writeExternal(ObjectOutput out)
throws IOException
{
out.writeInt(getType());
out.writeInt(getAction());
out.writeUTF(getName());
out.writeBoolean(getValue()!=null);
try
{
out.writeObject(getValue());
}
catch (Exception e)
{
System.out.println("Missing Value");
}
}
Following code reads object. Similar to read if the object is not serializable I try to read again to get read "Missing Value"
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException
{
this.type = in.readInt();
this.action = in.readInt();
this.name = in.readUTF();
boolean hasValue=in.readBoolean();
try{
this.value = in.readObject();
}
catch(Exception er)
{
System.out.println("Missing Value");
}
}
I am getting following error, and I am not quite sure what does it mean. Both of the functions are being called for multiple times. First the writeExternal function is called for all the objects and then the readExternal.
java.io.StreamCorruptedException: invalid type code: 4C
at java.io.ObjectInputStream$BlockDataInputStream.readBlockHeader(ObjectInputStream.java:2480)
at java.io.ObjectInputStream$BlockDataInputStream.refill(ObjectInputStream.java:2515)
at java.io.ObjectInputStream$BlockDataInputStream.read(ObjectInputStream.java:2587)
at java.io.DataInputStream.readInt(DataInputStream.java:387)
at java.io.ObjectInputStream$BlockDataInputStream.readInt(ObjectInputStream.java:2792)
at java.io.ObjectInputStream.readInt(ObjectInputStream.java:967)
EDIT
*Here is the code*
public class DeltaRequest
implements Externalizable
{
private LinkedList actions = new LinkedList();
private LinkedList actionPool = new LinkedList();
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException
{
AttributeInfo info = null;
if (this.actionPool.size() > 0) {
info = (AttributeInfo)this.actionPool.removeFirst();
info.readExternal(in);
this.actions.addLast(info);
}
}
public void writeExternal(ObjectOutput out)
throws IOException
{
out.writeUTF(getSessionId());
out.writeBoolean(this.recordAllActions);
out.writeInt(getSize());
for (int i = 0; i < getSize(); i++) {
AttributeInfo info = (AttributeInfo)this.actions.get(i);
info.writeExternal(out);
}
}
protected byte[] serialize()
throws IOException
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
writeExternal(oos);
oos.flush();
oos.close();
return bos.toByteArray();
}
private static class AttributeInfo implements Externalizable {
private String name = null;
private Object value = null;
private int action;
private int type;
public AttributeInfo() {
}
public AttributeInfo(int type, int action, String name, Object value) {
init(type, action, name, value);
}
public void init(int type, int action, String name, Object value)
{
this.name = name;
this.value = value;
this.action = action;
this.type = type;
}
public int getType() {
return this.type;
}
public int getAction() {
return this.action;
}
public Object getValue() {
return this.value;
}
public int hashCode() {
return this.name.hashCode();
}
public String getName() {
return this.name;
}
public void recycle() {
this.name = null;
this.value = null;
this.type = -1;
this.action = -1;
}
public boolean equals(Object o) {
if (!(o instanceof AttributeInfo)) return false;
AttributeInfo other = (AttributeInfo)o;
return other.getName().equals(getName());
}
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException
{
this.type = in.readInt();
this.action = in.readInt();
this.name = in.readUTF();
boolean hasValue=in.readBoolean();
try{
this.value = in.readObject();
}
catch(Exception er)
{
out.writeObject("Value Missing");
}
}
public void writeExternal(ObjectOutput out)
throws IOException
{
out.writeInt(getType());
out.writeInt(getAction());
out.writeUTF(getName());
out.writeBoolean(getValue()!=null);
try
{
out.writeObject(getValue());
}
catch (Exception e)
{
out.writeObject("Value Missing");
}
}
public String toString()
{
StringBuffer buf = new StringBuffer("AttributeInfo[type=");
buf.append(getType()).append(", action=").append(getAction());
buf.append(", name=").append(getName()).append(", value=").append(getValue());
buf.append(", addr=").append(super.toString()).append("]");
return buf.toString();
}
}
}
Code:
This is how the above function are called.
protected DeltaRequest deserializeDeltaRequest(DeltaSession objbb, byte[] data)
throws ClassNotFoundException, IOException
{
try
{
objbb.lock();
ReplicationStream ois = getReplicationStream(data);
objbb.getDeltaRequest().readExternal(ois);
ois.close();
return objbb.getDeltaRequest();
} finally {
objbb.unlock();
}
}
protected byte[] serializeDeltaRequest(DeltaSession objbb, DeltaRequest objAA)
throws IOException
{
try
{
objbb.lock();
return objAA.serialize();
} finally {
objbb.unlock();
}
}
DeltaManager
public class DeltaManager extends ClusterManagerBase
{
public Session createSession(String sessionId)
{
return createSession(sessionId, true);
}
public Session createSession(String sessionId, boolean distribute)
{
if ((this.maxActiveSessions >= 0) && (this.sessions.size() >= this.maxActiveSessions)) {
this.rejectedSessions += 1;
throw new IllegalStateException(sm.getString("deltaManager.createSession.ise"));
}
DeltaSession session = (DeltaSession)super.createSession(sessionId);
if (distribute) {
sendCreateSession(session.getId(), session);
}
if (log.isDebugEnabled())
log.debug(sm.getString("deltaManager.createSession.newSession", session.getId(), new Integer(this.sessions.size())));
return session;
}
protected void sendCreateSession(String sessionId, DeltaSession session)
{
if (this.cluster.getMembers().length > 0) {
SessionMessage msg = new SessionMessageImpl(getName(), 1, null, sessionId, sessionId + "-" + System.currentTimeMillis());
if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.sendMessage.newSession", this.name, sessionId));
msg.setTimestamp(session.getCreationTime());
this.counterSend_EVT_SESSION_CREATED += 1L;
send(msg);
}
}
protected DeltaRequest deserializeDeltaRequest(DeltaSession session, byte[] data)
throws ClassNotFoundException, IOException
{
try
{
session.lock();
ReplicationStream ois = getReplicationStream(data);
session.getDeltaRequest().readExternal(ois);
ois.close();
return session.getDeltaRequest();
} finally {
session.unlock();
}
}
protected byte[] serializeDeltaRequest(DeltaSession session, DeltaRequest deltaRequest)
throws IOException
{
try
{
session.lock();
return deltaRequest.serialize();
} finally {
session.unlock();
}
}
protected void deserializeSessions(byte[] data)
throws ClassNotFoundException, IOException
{
ClassLoader originalLoader = Thread.currentThread().getContextClassLoader();
ObjectInputStream ois = null;
try
{
ois = getReplicationStream(data);
Integer count = (Integer)ois.readObject();
int n = count.intValue();
for (int i = 0; i < n; i++) {
DeltaSession session = (DeltaSession)createEmptySession();
session.readObjectData(ois);
session.setManager(this);
session.setValid(true);
session.setPrimarySession(false);
session.access();
session.setAccessCount(0);
session.resetDeltaRequest();
if (findSession(session.getIdInternal()) == null) {
this.sessionCounter += 1;
} else {
this.sessionReplaceCounter += 1L;
if (log.isWarnEnabled()) log.warn(sm.getString("deltaManager.loading.existing.session", session.getIdInternal()));
}
add(session);
}
} catch (ClassNotFoundException e) {
log.error(sm.getString("deltaManager.loading.cnfe", e), e);
throw e;
} catch (IOException e) {
log.error(sm.getString("deltaManager.loading.ioe", e), e);
throw e;
}
finally {
try {
if (ois != null) ois.close();
}
catch (IOException f)
{
}
ois = null;
if (originalLoader != null) Thread.currentThread().setContextClassLoader(originalLoader);
}
}
protected byte[] serializeSessions(Session[] currentSessions)
throws IOException
{
ByteArrayOutputStream fos = null;
ObjectOutputStream oos = null;
try
{
fos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(new BufferedOutputStream(fos));
oos.writeObject(new Integer(currentSessions.length));
for (int i = 0; i < currentSessions.length; i++) {
((DeltaSession)currentSessions[i]).writeObjectData(oos);
}
oos.flush();
} catch (IOException e) {
log.error(sm.getString("deltaManager.unloading.ioe", e), e);
throw e;
} finally {
if (oos != null) {
try {
oos.close();
}
catch (IOException f) {
}
oos = null;
}
}
return fos.toByteArray();
}
public void start()
throws LifecycleException
{
if (!this.initialized) init();
if (this.started) {
return;
}
this.started = true;
this.lifecycle.fireLifecycleEvent("start", null);
generateSessionId();
try
{
Cluster cluster = getCluster();
if (cluster == null) {
Container context = getContainer();
if ((context != null) && ((context instanceof Context))) {
Container host = context.getParent();
if ((host != null) && ((host instanceof Host))) {
cluster = host.getCluster();
if ((cluster != null) && ((cluster instanceof CatalinaCluster))) {
setCluster((CatalinaCluster)cluster);
} else {
Container engine = host.getParent();
if ((engine != null) && ((engine instanceof Engine))) {
cluster = engine.getCluster();
if ((cluster != null) && ((cluster instanceof CatalinaCluster)))
setCluster((CatalinaCluster)cluster);
}
else {
cluster = null;
}
}
}
}
}
if (cluster == null) {
log.error(sm.getString("deltaManager.noCluster", getName()));
return;
}
if (log.isInfoEnabled()) {
String type = "unknown";
if ((cluster.getContainer() instanceof Host))
type = "Host";
else if ((cluster.getContainer() instanceof Engine)) {
type = "Engine";
}
log.info(sm.getString("deltaManager.registerCluster", getName(), type, cluster.getClusterName()));
}
if (log.isInfoEnabled()) log.info(sm.getString("deltaManager.startClustering", getName()));
cluster.registerManager(this);
getAllClusterSessions();
}
catch (Throwable t) {
log.error(sm.getString("deltaManager.managerLoad"), t);
}
}
public synchronized void getAllClusterSessions()
{
if ((this.cluster != null) && (this.cluster.getMembers().length > 0)) {
long beforeSendTime = System.currentTimeMillis();
Member mbr = findSessionMasterMember();
if (mbr == null) {
return;
}
SessionMessage msg = new SessionMessageImpl(getName(), 4, null, "GET-ALL", "GET-ALL-" + getName());
this.stateTransferCreateSendTime = beforeSendTime;
this.counterSend_EVT_GET_ALL_SESSIONS += 1L;
this.stateTransfered = false;
try
{
synchronized (this.receivedMessageQueue) {
this.receiverQueue = true;
}
this.cluster.send(msg, mbr);
if (log.isWarnEnabled()) log.warn(sm.getString("deltaManager.waitForSessionState", getName(), mbr, Integer.valueOf(getStateTransferTimeout())));
waitForSendAllSessions(beforeSendTime);
} finally {
synchronized (this.receivedMessageQueue) {
for (Iterator iter = this.receivedMessageQueue.iterator(); iter.hasNext(); ) {
SessionMessage smsg = (SessionMessage)iter.next();
if (!this.stateTimestampDrop) {
messageReceived(smsg, smsg.getAddress() != null ? smsg.getAddress() : null);
}
else if ((smsg.getEventType() != 4) && (smsg.getTimestamp() >= this.stateTransferCreateSendTime))
{
messageReceived(smsg, smsg.getAddress() != null ? smsg.getAddress() : null);
}
else if (log.isWarnEnabled()) {
log.warn(sm.getString("deltaManager.dropMessage", getName(), smsg.getEventTypeString(), new Date(this.stateTransferCreateSendTime), new Date(smsg.getTimestamp())));
}
}
this.receivedMessageQueue.clear();
this.receiverQueue = false;
}
}
}
else if (log.isInfoEnabled()) { log.info(sm.getString("deltaManager.noMembers", getName())); }
}
protected void registerSessionAtReplicationValve(DeltaSession session)
{
if ((this.replicationValve == null) &&
((this.container instanceof StandardContext)) && (((StandardContext)this.container).getCrossContext())) {
Cluster cluster = getCluster();
if ((cluster != null) && ((cluster instanceof CatalinaCluster))) {
Valve[] valves = ((CatalinaCluster)cluster).getValves();
if ((valves != null) && (valves.length > 0)) {
for (int i = 0; (this.replicationValve == null) && (i < valves.length); i++) {
if ((valves[i] instanceof ReplicationValve)) this.replicationValve = ((ReplicationValve)valves[i]);
}
if ((this.replicationValve == null) && (log.isDebugEnabled())) {
log.debug("no ReplicationValve found for CrossContext Support");
}
}
}
}
if (this.replicationValve != null)
this.replicationValve.registerReplicationSession(session);
}
protected Member findSessionMasterMember()
{
Member mbr = null;
Member[] mbrs = this.cluster.getMembers();
if (mbrs.length != 0) mbr = mbrs[0];
if ((mbr == null) && (log.isWarnEnabled())) log.warn(sm.getString("deltaManager.noMasterMember", getName(), ""));
if ((mbr != null) && (log.isDebugEnabled())) log.warn(sm.getString("deltaManager.foundMasterMember", getName(), mbr));
return mbr;
}
public void messageDataReceived(ClusterMessage cmsg)
{
if ((cmsg != null) && ((cmsg instanceof SessionMessage))) {
SessionMessage msg = (SessionMessage)cmsg;
switch (msg.getEventType()) {
case 1:
case 2:
case 3:
case 4:
case 13:
synchronized (this.receivedMessageQueue) {
if (this.receiverQueue) {
this.receivedMessageQueue.add(msg);
return;
}
}
break;
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12: } messageReceived(msg, msg.getAddress() != null ? msg.getAddress() : null);
}
}
public ClusterMessage requestCompleted(String sessionId)
{
return requestCompleted(sessionId, false);
}
public ClusterMessage requestCompleted(String sessionId, boolean expires)
{
DeltaSession session = null;
try {
session = (DeltaSession)findSession(sessionId);
DeltaRequest deltaRequest = session.getDeltaRequest();
session.lock();
msg = null;
boolean isDeltaRequest = false;
synchronized (deltaRequest) {
isDeltaRequest = deltaRequest.getSize() > 0;
if (isDeltaRequest) {
this.counterSend_EVT_SESSION_DELTA += 1L;
byte[] data = serializeDeltaRequest(session, deltaRequest);
msg = new SessionMessageImpl(getName(), 13, data, sessionId, sessionId + "-" + System.currentTimeMillis());
session.resetDeltaRequest();
}
}
if (!isDeltaRequest) {
if ((!expires) && (!session.isPrimarySession())) {
this.counterSend_EVT_SESSION_ACCESSED += 1L;
msg = new SessionMessageImpl(getName(), 3, null, sessionId, sessionId + "-" + System.currentTimeMillis());
if (log.isDebugEnabled()) {
log.debug(sm.getString("deltaManager.createMessage.accessChangePrimary", getName(), sessionId));
}
}
}
else if (log.isDebugEnabled()) {
log.debug(sm.getString("deltaManager.createMessage.delta", getName(), sessionId));
}
if (!expires)
session.setPrimarySession(true);
long replDelta;
if ((!expires) && (msg == null)) {
replDelta = System.currentTimeMillis() - session.getLastTimeReplicated();
if (replDelta > getMaxInactiveInterval() * 1000) {
this.counterSend_EVT_SESSION_ACCESSED += 1L;
msg = new SessionMessageImpl(getName(), 3, null, sessionId, sessionId + "-" + System.currentTimeMillis());
if (log.isDebugEnabled()) {
log.debug(sm.getString("deltaManager.createMessage.access", getName(), sessionId));
}
}
}
if (msg != null) {
session.setLastTimeReplicated(System.currentTimeMillis());
msg.setTimestamp(session.getLastTimeReplicated());
}
return msg;
}
catch (IOException x)
{
SessionMessage msg;
log.error(sm.getString("deltaManager.createMessage.unableCreateDeltaRequest", sessionId), x);
return null;
} finally {
if (session != null) session.unlock();
}
}
protected void messageReceived(SessionMessage msg, Member sender)
{
if ((doDomainReplication()) && (!checkSenderDomain(msg, sender))) {
return;
}
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
try
{
ClassLoader[] loaders = getClassLoaders();
if ((loaders != null) && (loaders.length > 0)) Thread.currentThread().setContextClassLoader(loaders[0]);
if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.eventType", getName(), msg.getEventTypeString(), sender));
switch (msg.getEventType()) {
case 4:
handleGET_ALL_SESSIONS(msg, sender);
break;
case 12:
handleALL_SESSION_DATA(msg, sender);
break;
case 14:
handleALL_SESSION_TRANSFERCOMPLETE(msg, sender);
break;
case 1:
handleSESSION_CREATED(msg, sender);
break;
case 2:
handleSESSION_EXPIRED(msg, sender);
break;
case 3:
handleSESSION_ACCESSED(msg, sender);
break;
case 13:
handleSESSION_DELTA(msg, sender);
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
}
} catch (Exception x) { log.error(sm.getString("deltaManager.receiveMessage.error", getName()), x);
} finally {
Thread.currentThread().setContextClassLoader(contextLoader);
}
}
protected void handleALL_SESSION_TRANSFERCOMPLETE(SessionMessage msg, Member sender)
{
this.counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE += 1;
if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.transfercomplete", getName(), sender.getHost(), new Integer(sender.getPort())));
this.stateTransferCreateSendTime = msg.getTimestamp();
this.stateTransfered = true;
}
protected void handleSESSION_DELTA(SessionMessage msg, Member sender)
throws IOException, ClassNotFoundException
{
this.counterReceive_EVT_SESSION_DELTA += 1L;
byte[] delta = msg.getSession();
DeltaSession session = (DeltaSession)findSession(msg.getSessionID());
if (session != null) {
if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.delta", getName(), msg.getSessionID())); try
{
session.lock();
DeltaRequest dreq = deserializeDeltaRequest(session, delta);
dreq.execute(session, this.notifyListenersOnReplication);
session.setPrimarySession(false);
} finally {
session.unlock();
}
}
}
protected void handleSESSION_CREATED(SessionMessage msg, Member sender)
{
this.counterReceive_EVT_SESSION_CREATED += 1L;
if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.createNewSession", getName(), msg.getSessionID()));
DeltaSession session = (DeltaSession)createEmptySession();
session.setManager(this);
session.setValid(true);
session.setPrimarySession(false);
session.setCreationTime(msg.getTimestamp());
session.setMaxInactiveInterval(getMaxInactiveInterval());
session.access();
if (this.notifySessionListenersOnReplication) {
session.setId(msg.getSessionID());
} else {
session.setIdInternal(msg.getSessionID());
add(session);
}
session.resetDeltaRequest();
session.endAccess();
}
protected void handleALL_SESSION_DATA(SessionMessage msg, Member sender)
throws ClassNotFoundException, IOException
{
this.counterReceive_EVT_ALL_SESSION_DATA += 1L;
if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.allSessionDataBegin", getName()));
byte[] data = msg.getSession();
deserializeSessions(data);
if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.allSessionDataAfter", getName()));
}
protected void handleGET_ALL_SESSIONS(SessionMessage msg, Member sender)
throws IOException
{
this.counterReceive_EVT_GET_ALL_SESSIONS += 1L;
if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.unloadingBegin", getName()));
Session[] currentSessions = findSessions();
long findSessionTimestamp = System.currentTimeMillis();
if (isSendAllSessions()) {
sendSessions(sender, currentSessions, findSessionTimestamp);
}
else {
int len = currentSessions.length < getSendAllSessionsSize() ? currentSessions.length : getSendAllSessionsSize();
Session[] sendSessions = new Session[len];
for (int i = 0; i < currentSessions.length; i += getSendAllSessionsSize()) {
len = i + getSendAllSessionsSize() > currentSessions.length ? currentSessions.length - i : getSendAllSessionsSize();
System.arraycopy(currentSessions, i, sendSessions, 0, len);
sendSessions(sender, sendSessions, findSessionTimestamp);
if (getSendAllSessionsWaitTime() > 0)
try {
Thread.sleep(getSendAllSessionsWaitTime());
}
catch (Exception sleep)
{
}
}
}
SessionMessage newmsg = new SessionMessageImpl(this.name, 14, null, "SESSION-STATE-TRANSFERED", "SESSION-STATE-TRANSFERED" + getName());
newmsg.setTimestamp(findSessionTimestamp);
if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.createMessage.allSessionTransfered", getName()));
this.counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE += 1;
this.cluster.send(newmsg, sender);
}
protected void sendSessions(Member sender, Session[] currentSessions, long sendTimestamp)
throws IOException
{
byte[] data = serializeSessions(currentSessions);
if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.receiveMessage.unloadingAfter", getName()));
SessionMessage newmsg = new SessionMessageImpl(this.name, 12, data, "SESSION-STATE", "SESSION-STATE-" + getName());
newmsg.setTimestamp(sendTimestamp);
if (log.isDebugEnabled()) log.debug(sm.getString("deltaManager.createMessage.allSessionData", getName()));
this.counterSend_EVT_ALL_SESSION_DATA += 1L;
this.cluster.send(newmsg, sender);
}
}
The problem here is that you are calling
this.writeExternal(oos);
instead of
oos.writeObject(this);
so the ObjectOutputStream never gets the chance to write the object preamble.
Similarly, you must call
Object o = ois.readObject();
rather than
Object o = this.readExternal(ois);
Re your non-serializable object, you should write a special object. At the moment you are treating every possible exception as just a missing object, when it could be a huge number of other things.

HTTP Post request on BlackBerry

I am trying to send a json string , from my BlackBerry OS < 7.X application to my Server. I am trying to use an HTTP Post request. What i have done so far is :
String httpURL = "http://ip_of_my_server/phpServer/receiver2.php/" + jsonString;
try {
HttpConnection httpConn;
httpConn = (HttpConnection) Connector.open(httpURL + getConnectionString());
httpConn.setRequestMethod(HttpConnection.POST);
httpConn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
DataOutputStream _outStream = new DataOutputStream(httpConn.openDataOutputStream());
byte[] request_body = httpURL.getBytes();
for (int i = 0; i < request_body.length; i++) {
_outStream.writeByte(request_body[i]);
}
DataInputStream _inputStream = new DataInputStream(httpConn.openInputStream());
StringBuffer _responseMessage = new StringBuffer();
int ch;
while ((ch = _inputStream.read()) != -1) {
_responseMessage.append((char) ch);
}
String res = (_responseMessage.toString());
String response = res.trim();
System.out.println("!!!!!!!!!!!!!! Response is: " + response);
httpConn.close();
} catch (Exception e) {
Dialog.alert("Error - " + e.toString());
}
The code works in a way that i dont fully understand. The author of the above code suggested to use as an httpURL the URL of the server + my json string. The final result is that on my server instead of arriving the json string , is arriving a string like that :
http://ip_of_my_server/phpServer/receiver2.php/ + jsonString
I am not familiar with java. I have previously done this for WP7 and iOS and in the httpUrl i put my servers URL and then with a command i was "appending" my json string to the http request and everything worked as expected.
How can i append the json string to the above HttpRequest , instead of adding it to the URL so that in the server arrives the JSON String only?
EDIT (providing the rest of the code that was used)
//used to specify connection type ( wifi - 3g - etc )
public static String getConnectionString() {
String connectionString = null;
// Wifi is the preferred transmission method
if (WLANInfo.getWLANState() == WLANInfo.WLAN_STATE_CONNECTED) {
connectionString = ";interface=wifi";
}
// Is the carrier network the only way to connect?
else if ((CoverageInfo.getCoverageStatus() & CoverageInfo.COVERAGE_DIRECT) == CoverageInfo.COVERAGE_DIRECT) {
String carrierUid = getCarrierBIBSUid();
if (carrierUid == null) {
// Has carrier coverage, but not BIBS. So use the carrier's TCP network
connectionString = ";deviceside=true";
} else {
// otherwise, use the Uid to construct a valid carrier BIBS request
connectionString = ";deviceside=false;connectionUID="+carrierUid + ";ConnectionType=mds-public";
}
}
// Check for an MDS connection instead (BlackBerry Enterprise Server)
else if ((CoverageInfo.getCoverageStatus() & CoverageInfo.COVERAGE_MDS) == CoverageInfo.COVERAGE_MDS) {
connectionString = ";deviceside=false";
}
// If there is no connection available abort to avoid hassling the user unnecessarily
else if (CoverageInfo.getCoverageStatus() == CoverageInfo.COVERAGE_NONE) {
connectionString = "none";
}
// In theory, all bases are covered by now so this shouldn't be reachable.But hey, just in case ...
else {
connectionString = ";deviceside=true";
}
System.out.println("!!!!!!!!!!!!!! Connection type is: " + connectionString);
return connectionString;
}
/**
* Looks through the phone's service book for a carrier provided BIBS
* network
*
* #return The uid used to connect to that network.
*/
private synchronized static String getCarrierBIBSUid() {
ServiceRecord[] records = ServiceBook.getSB().getRecords();
int currentRecord;
for (currentRecord = 0; currentRecord < records.length; currentRecord++) {
if (records[currentRecord].getCid().toLowerCase().equals("ippp")) {
if (records[currentRecord].getName().toLowerCase()
.indexOf("bibs") >= 0) {
return records[currentRecord].getUid();
}
}
}
return null;
}
The the first line should be simply your URL
String httpURL = "http://ip_of_my_server/phpServer/receiver2.php";
And you should only send the json string to the server as request.
instead of byte[] request_body = httpURL.getBytes();
use byte[] request_body = jsonString.getBytes();
Here is the method for OS 5.0 and above
public static HttpConnection getHttpConnection(String url, byte[] postData) {
HttpConnection conn = null;
OutputStream out = null;
try {
conn = (HttpConnection) new ConnectionFactory().getConnection(url).getConnection();
if (conn != null) {
if (postData == null) {
conn.setRequestMethod(HttpConnection.GET);
conn.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0");
} else {
conn.setRequestMethod(HttpConnection.POST);
conn.setRequestProperty("Content-Length", String.valueOf(postData.length));
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0");
out = conn.openOutputStream();
out.write(postData);
out.flush();
}
if (conn.getResponseCode() != 0) {
return conn;
}
}
} catch (Exception e) {
} finally {
try {
out.close();
} catch (Exception e2) {
}
}
//Only if exception occurs, we close the connection.
//Otherwise the caller should close the connection himself.
try {
conn.close();
} catch (Exception e1) {
}
return null;
}
Here is the complete class if you want it to work with OS 4.2 and above. You may need to replace the constant COVERAGE_DIRECT by its value 1, if you want to compile it with < 4.5.
public class ConnectionHelper {
/**
* Returns the working connection type. The connection types can be BIS, BES, TCP, WAP2, TCPIP
*/
public static HttpConnection getHttpConnection(String url, byte[] postData) {
int[] preferredOrder = new int[] { CONNECTION_WIFI, CONNECTION_BIS, CONNECTION_BES, CONNECTION_UNITE, CONNECTION_WAP2, CONNECTION_TCPIP, };
for (int i = 0; i < preferredOrder.length; i++) {
int type = preferredOrder[i];
if (isPresent(type)) {
HttpConnection conn = null;
OutputStream out = null;
try {
conn = (HttpConnection) Connector.open(convertURL(type, url));
if (conn != null) {
if (postData == null) {
conn.setRequestMethod(HttpConnection.GET);
conn.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0");
} else {
conn.setRequestMethod(HttpConnection.POST);
conn.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_LENGTH, String.valueOf(postData.length));
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0");
out = conn.openOutputStream();
out.write(postData);
out.flush();
}
if (conn.getResponseCode() != 0) {
return conn;
}
}
} catch (Exception e) {
} finally {
try {
out.close();
} catch (Exception e2) {
}
}
}
}
// Only if exception occurs, we close the connection.
// Otherwise the caller should close the connection himself.
try {
conn.close();
} catch (Exception e1) {
}
return null;
}
/** Stores transport ServiceBooks if found. Otherwise, null */
private static ServiceRecord srMDS, srWiFi, srBIS, srWAP2, srUnite;
private static final int CONNECTION_DEFAULT = 0;
private static final int CONNECTION_BIS = 1;
private static final int CONNECTION_BES = 2;
private static final int CONNECTION_TCPIP = 3;
private static final int CONNECTION_WIFI = 4;
private static final int CONNECTION_WAP2 = 5;
private static final int CONNECTION_UNITE = 6;
private static final int CONFIG_TYPE_BES = 1;
private static final String UNITE_NAME = "Unite";
private static void checkTransportAvailability() {
initializeTransportAvailability();
}
/**
* Initializes the ServiceRecord instances for each transport (if available). Otherwise leaves it null. Also determines if sufficient coverage is available for each transport
* and sets coverage* flags.
*/
private static void initializeTransportAvailability() {
ServiceBook sb = ServiceBook.getSB();
ServiceRecord[] records = sb.getRecords();
for (int i = 0; i < records.length; i++) {
ServiceRecord myRecord = records[i];
String cid, uid;
if (myRecord.isValid() && !myRecord.isDisabled()) {
cid = myRecord.getCid().toLowerCase();
uid = myRecord.getUid().toLowerCase();
// BIS
if (cid.indexOf("ippp") != -1 && uid.indexOf("gpmds") != -1) {
srBIS = myRecord;
}
// BES
if (cid.indexOf("ippp") != -1 && uid.indexOf("gpmds") == -1) {
srMDS = myRecord;
}
// WiFi
if (cid.indexOf("wptcp") != -1 && uid.indexOf("wifi") != -1) {
srWiFi = myRecord;
}
// Wap2.0
if (cid.indexOf("wptcp") != -1 && uid.indexOf("wifi") == -1 && uid.indexOf("mms") == -1) {
srWAP2 = myRecord;
}
// Unite
if (getConfigType(myRecord) == CONFIG_TYPE_BES && myRecord.getName().equals(UNITE_NAME)) {
srUnite = myRecord;
}
}
}
}
/**
* Gets the config type of a ServiceRecord using getDataInt below
*
* #param record
* A ServiceRecord
* #return configType of the ServiceRecord
*/
private static int getConfigType(ServiceRecord record) {
return getDataInt(record, 12);
}
/**
* Gets the config type of a ServiceRecord. Passing 12 as type returns the configType.
*
* #param record
* A ServiceRecord
* #param type
* dataType
* #return configType
*/
private static int getDataInt(ServiceRecord record, int type) {
DataBuffer buffer = null;
buffer = getDataBuffer(record, type);
if (buffer != null) {
try {
return ConverterUtilities.readInt(buffer);
} catch (EOFException e) {
return -1;
}
}
return -1;
}
/**
* Utility Method for getDataInt()
*/
private static DataBuffer getDataBuffer(ServiceRecord record, int type) {
byte[] data = record.getApplicationData();
if (data != null) {
DataBuffer buffer = new DataBuffer(data, 0, data.length, true);
try {
buffer.readByte();
} catch (EOFException e1) {
return null;
}
if (ConverterUtilities.findType(buffer, type)) {
return buffer;
}
}
return null;
}
private static String convertURL(int connectionType, String url) {
switch (connectionType) {
case CONNECTION_BES:
url += ";deviceside=false";
break;
case CONNECTION_BIS:
url += ";deviceside=false" + ";ConnectionType=mds-public";
break;
case CONNECTION_TCPIP:
url += ";deviceside=true";
break;
case CONNECTION_WIFI:
url += ";interface=wifi";
break;
case CONNECTION_WAP2:
url += ";deviceside=true;ConnectionUID=" + srWAP2.getUid();
break;
case CONNECTION_UNITE:
url += ";deviceside=false;ConnectionUID=" + srUnite.getUid();
break;
}
return url;
}
private static boolean isPresent(int connectionType) {
checkTransportAvailability();
switch (connectionType) {
case CONNECTION_BIS:
return (srBIS != null && CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_BIS_B));
case CONNECTION_BES:
return (srMDS != null && CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_MDS));
case CONNECTION_WIFI:
return (srWiFi != null && CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_DIRECT, RadioInfo.WAF_WLAN, false));
case CONNECTION_TCPIP:
return (CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_DIRECT));
case CONNECTION_WAP2:
return (srWAP2 != null && CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_DIRECT));
case CONNECTION_UNITE:
return (srUnite != null && CoverageInfo.isCoverageSufficient(CoverageInfo.COVERAGE_MDS));
case CONNECTION_DEFAULT:
return true;
}
return false;
}
}
And finally post your data.
public void sendJson(String jsonString) {
String httpURL = "http://ip_of_my_server/phpServer/receiver2.php";
HttpConnection httpConn = null;
try {
httpConn = getHttpConnection(httpURL, jsonString.getBytes());
if(httpConn.getResponseCode() == 200) {
//If you need the output, then read it. Otherwise comment it.
byte[] data = IOUtilities.streamToBytes(httpConn.openInputStream());
String response = new String(data);
System.out.println("!!!!!!!!!!!!!! Response is: " + response);
}
} catch (Exception e) {
}
finally {
try {
httpConn.close();
} catch (Exception e2) {
}
}
}

Getting metadata from SHOUTcast using IcyStreamMeta

I am writing an app for Android that grabs meta data from SHOUTcast mp3 streams. I am using a pretty nifty class I found online that I slightly modified, but I am still having 2 problems.
1) I have to continuously ping the server to update the metadata using a TimerTask. I am not fond of this approach but it was all I could think of.
2) There is a metric tonne of garbage collection while my app is running. Removing the TimerTask got rid of the garbage collection issue so I am not sure if I am just doing it wrong or if this is normal.
Here is the class I am using:
public class IcyStreamMeta {
protected URL streamUrl;
private Map<String, String> metadata;
private boolean isError;
public IcyStreamMeta(URL streamUrl) {
setStreamUrl(streamUrl);
isError = false;
}
/**
* Get artist using stream's title
*
* #return String
* #throws IOException
*/
public String getArtist() throws IOException {
Map<String, String> data = getMetadata();
if (!data.containsKey("StreamTitle"))
return "";
try {
String streamTitle = data.get("StreamTitle");
String title = streamTitle.substring(0, streamTitle.indexOf("-"));
return title.trim();
}catch (StringIndexOutOfBoundsException e) {
return "";
}
}
/**
* Get title using stream's title
*
* #return String
* #throws IOException
*/
public String getTitle() throws IOException {
Map<String, String> data = getMetadata();
if (!data.containsKey("StreamTitle"))
return "";
try {
String streamTitle = data.get("StreamTitle");
String artist = streamTitle.substring(streamTitle.indexOf("-")+1);
return artist.trim();
} catch (StringIndexOutOfBoundsException e) {
return "";
}
}
public Map<String, String> getMetadata() throws IOException {
if (metadata == null) {
refreshMeta();
}
return metadata;
}
public void refreshMeta() throws IOException {
retreiveMetadata();
}
private void retreiveMetadata() throws IOException {
URLConnection con = streamUrl.openConnection();
con.setRequestProperty("Icy-MetaData", "1");
con.setRequestProperty("Connection", "close");
//con.setRequestProperty("Accept", null);
con.connect();
int metaDataOffset = 0;
Map<String, List<String>> headers = con.getHeaderFields();
InputStream stream = con.getInputStream();
if (headers.containsKey("icy-metaint")) {
// Headers are sent via HTTP
metaDataOffset = Integer.parseInt(headers.get("icy-metaint").get(0));
} else {
// Headers are sent within a stream
StringBuilder strHeaders = new StringBuilder();
char c;
while ((c = (char)stream.read()) != -1) {
strHeaders.append(c);
if (strHeaders.length() > 5 && (strHeaders.substring((strHeaders.length() - 4), strHeaders.length()).equals("\r\n\r\n"))) {
// end of headers
break;
}
}
// Match headers to get metadata offset within a stream
Pattern p = Pattern.compile("\\r\\n(icy-metaint):\\s*(.*)\\r\\n");
Matcher m = p.matcher(strHeaders.toString());
if (m.find()) {
metaDataOffset = Integer.parseInt(m.group(2));
}
}
// In case no data was sent
if (metaDataOffset == 0) {
isError = true;
return;
}
// Read metadata
int b;
int count = 0;
int metaDataLength = 4080; // 4080 is the max length
boolean inData = false;
StringBuilder metaData = new StringBuilder();
// Stream position should be either at the beginning or right after headers
while ((b = stream.read()) != -1) {
count++;
// Length of the metadata
if (count == metaDataOffset + 1) {
metaDataLength = b * 16;
}
if (count > metaDataOffset + 1 && count < (metaDataOffset + metaDataLength)) {
inData = true;
} else {
inData = false;
}
if (inData) {
if (b != 0) {
metaData.append((char)b);
}
}
if (count > (metaDataOffset + metaDataLength)) {
break;
}
}
// Set the data
metadata = IcyStreamMeta.parseMetadata(metaData.toString());
// Close
stream.close();
}
public boolean isError() {
return isError;
}
public URL getStreamUrl() {
return streamUrl;
}
public void setStreamUrl(URL streamUrl) {
this.metadata = null;
this.streamUrl = streamUrl;
this.isError = false;
}
public static Map<String, String> parseMetadata(String metaString) {
Map<String, String> metadata = new HashMap<String, String>();
String[] metaParts = metaString.split(";");
Pattern p = Pattern.compile("^([a-zA-Z]+)=\\'([^\\']*)\\'$");
Matcher m;
for (int i = 0; i < metaParts.length; i++) {
m = p.matcher(metaParts[i]);
if (m.find()) {
metadata.put((String)m.group(1), (String)m.group(2));
}
}
return metadata;
}
}
And here is my timer:
private void getMeta() {
timer.schedule(new TimerTask() {
public void run() {
try {
icy = new IcyStreamMeta(new URL(stationUrl));
runOnUiThread(new Runnable() {
public void run() {
try {
artist.setText(icy.getArtist());
title.setText(icy.getTitle());
} catch (IOException e) {
e.printStackTrace();
} catch (StringIndexOutOfBoundsException e) {
e.printStackTrace();
}
}
});
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
},0,5000);
}
Much appreciation for any assistance!
I've replaced the IcyStreamMeta class in my program and am getting the meta data from the 7.html file that is a part of the SHOUTcast spec. Far less data usage and all that so I feel it is a better option.
I am still using the TimerTask, which is acceptable. There is practically no GC any more and I am happy with using 7.html and a little regex. :)

Categories

Resources