public static void main(String args[]) throws Exception { String inputFile = "samplein.txt"; String outputFile = "sampleout.txt"; RandomAccessFile inf = new RandomAccessFile(inputFile, "r"); RandomAccessFile outf = new RandomAccessFile(outputFile, "rw"); long inputLength = new File(inputFile).length(); FileChannel inc = inf.getChannel(); FileChannel outc = outf.getChannel(); MappedByteBuffer inputData = inc.map(FileChannel.MapMode.READ_ONLY, 0, inputLength); Charset latin1 = Charset.forName("ISO-8859-1"); CharsetDecoder decoder = latin1.newDecoder(); CharsetEncoder encoder = latin1.newEncoder(); CharBuffer cb = decoder.decode(inputData); // Process char data here ByteBuffer outputData = encoder.encode(cb); outc.write(outputData); inf.close(); outf.close(); }
// Check if the datagramsocket adaptor can send with a packet // that has not been initialized with an address; the legacy // datagram socket will send in this case private static void test2() throws Exception { DatagramChannel sndChannel = DatagramChannel.open(); sndChannel.socket().bind(null); InetSocketAddress sender = new InetSocketAddress(InetAddress.getLocalHost(), sndChannel.socket().getLocalPort()); DatagramChannel rcvChannel = DatagramChannel.open(); rcvChannel.socket().bind(null); InetSocketAddress receiver = new InetSocketAddress(InetAddress.getLocalHost(), rcvChannel.socket().getLocalPort()); rcvChannel.connect(sender); sndChannel.connect(receiver); byte b[] = "hello".getBytes("UTF-8"); DatagramPacket pkt = new DatagramPacket(b, b.length); sndChannel.socket().send(pkt); ByteBuffer bb = ByteBuffer.allocate(256); rcvChannel.receive(bb); bb.flip(); CharBuffer cb = Charset.forName("US-ASCII").newDecoder().decode(bb); if (!cb.toString().startsWith("h")) throw new RuntimeException("Test failed"); // Check that the pkt got set with the target address; // This is legacy behavior if (!pkt.getSocketAddress().equals(receiver)) throw new RuntimeException("Test failed"); rcvChannel.close(); sndChannel.close(); }
public static void main(String[] args) throws MessagingException, IOException { Properties props = new Properties(); try (InputStream in = Files.newInputStream(Paths.get("mail", "mail.properties"))) { props.load(in); } List<String> lines = Files.readAllLines(Paths.get(args[0]), Charset.forName("UTF-8")); String from = lines.get(0); String to = lines.get(1); String subject = lines.get(2); StringBuilder builder = new StringBuilder(); for (int i = 3; i < lines.size(); i++) { builder.append(lines.get(i)); builder.append("\n"); } Console console = System.console(); String password = new String(console.readPassword("Password: ")); Session mailSession = Session.getDefaultInstance(props); // mailSession.setDebug(true); MimeMessage message = new MimeMessage(mailSession); message.setFrom(new InternetAddress(from)); message.addRecipient(RecipientType.TO, new InternetAddress(to)); message.setSubject(subject); message.setText(builder.toString()); Transport tr = mailSession.getTransport(); try { tr.connect(null, password); tr.sendMessage(message, message.getAllRecipients()); } finally { tr.close(); } }
/** * Constructor. * * @param enc encoding * @throws IOException I/O exception */ private Generic(final String enc) throws IOException { try { csd = Charset.forName(enc).newDecoder(); } catch (final Exception ex) { throw new EncodingException(ex); } }
// Check if DatagramChannel.send while connected can include // address without throwing private static void test1() throws Exception { DatagramChannel sndChannel = DatagramChannel.open(); sndChannel.socket().bind(null); InetSocketAddress sender = new InetSocketAddress(InetAddress.getLocalHost(), sndChannel.socket().getLocalPort()); DatagramChannel rcvChannel = DatagramChannel.open(); rcvChannel.socket().bind(null); InetSocketAddress receiver = new InetSocketAddress(InetAddress.getLocalHost(), rcvChannel.socket().getLocalPort()); rcvChannel.connect(sender); sndChannel.connect(receiver); ByteBuffer bb = ByteBuffer.allocate(256); bb.put("hello".getBytes()); bb.flip(); int sent = sndChannel.send(bb, receiver); bb.clear(); rcvChannel.receive(bb); bb.flip(); CharBuffer cb = Charset.forName("US-ASCII").newDecoder().decode(bb); if (!cb.toString().startsWith("h")) throw new RuntimeException("Test failed"); rcvChannel.close(); sndChannel.close(); }
public static void main(String[] arguments) { try { // read byte data into a byte buffer String data = "friends.dat"; FileInputStream inData = new FileInputStream(data); FileChannel inChannel = inData.getChannel(); long inSize = inChannel.size(); ByteBuffer source = ByteBuffer.allocate((int) inSize); inChannel.read(source, 0); source.position(0); System.out.println("Original byte data:"); for (int i = 0; source.remaining() > 0; i++) { System.out.print(source.get() + " "); } // convert byte data into character data source.position(0); Charset ascii = Charset.forName("US-ASCII"); CharsetDecoder toAscii = ascii.newDecoder(); CharBuffer destination = toAscii.decode(source); destination.position(0); System.out.println("\n\nNew character data:"); for (int i = 0; destination.remaining() > 0; i++) { System.out.print(destination.get()); } System.out.println(); } catch (FileNotFoundException fne) { System.out.println(fne.getMessage()); } catch (IOException ioe) { System.out.println(ioe.getMessage()); } }
/** * Constructor. * * @param os output stream * @param sopts serializer options * @throws QueryIOException query I/O exception */ protected OutputSerializer(final OutputStream os, final SerializerOptions sopts) throws QueryIOException { this.sopts = sopts; indent = sopts.yes(INDENT); // project-specific options indents = sopts.get(INDENTS); tab = sopts.yes(TABULATOR) ? '\t' : ' '; encoding = Strings.normEncoding(sopts.get(ENCODING), true); PrintOutput po; if (encoding == Strings.UTF8) { po = PrintOutput.get(os); } else { try { po = new EncoderOutput(os, Charset.forName(encoding)); } catch (final Exception ex) { throw SERENCODING_X.getIO(encoding); } } final int limit = sopts.get(LIMIT); if (limit != -1) po.setLimit(limit); final byte[] nl = token(sopts.get(NEWLINE).newline()); if (nl.length != 1 || nl[0] != '\n') po = new NewlineOutput(po, nl); out = po; }
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setCharacterEncoding("UTF-8"); HttpSession user = req.getSession(); PrintWriter out = resp.getWriter(); SpejdResultAnalyser result = null; JsonObject response; JsonReader jsonReader = Json.createReader(new InputStreamReader(req.getInputStream(), StandardCharsets.ISO_8859_1)); JsonObject jsonObject = jsonReader.readObject(); jsonReader.close(); System.out.println("REQUEST"); System.out.println(jsonObject); String originalText = jsonObject.getString("text"); int space = jsonObject.getInt("space"); String xml = getXml(originalText, user.getId()); try { result = new SpejdResultAnalyser(xml.replace("SYSTEM \"xcesAnaIPI.dtd\"", "")); } catch (ParserConfigurationException | SAXException e) { out.println(e.toString()); } assert result != null; /** do analysis of xml spejd result */ SubstantivePairs pairs = result.doAnalysis().makePair(space); /** * create json response { text: ... xml: ... pairs: [ { subst1: ... subst2: ... quantity: ... }, * ...] } */ JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); for (SubstantivePair pair : pairs) { arrayBuilder.add( Json.createObjectBuilder() .add("subst1", pair.getSubst1()) .add("subst2", pair.getSubst2()) .add("quantity", pair.getQuantity())); } Charset.forName("UTF-8").encode(originalText); JsonArray array = arrayBuilder.build(); response = Json.createObjectBuilder() .add("text", originalText) .add("xml", xml) .add("pairs", array) .build(); System.out.println("RESPONSE"); System.out.println(response); out.print(response); }
/** * Get text content of a source file. * * @param path The canonical path of source file. * @param charset Source file encoding. * @return Source file content. */ public String read(String path, String charset) { String str = null; byte[] bin = read(path); try { str = Charset.forName(charset).newDecoder().decode(ByteBuffer.wrap(bin)).toString(); } catch (CharacterCodingException e) { App.exit("Cannot read " + path + " as " + charset + " encoded file"); } return str; }
/** * Tests response handling with specified charset in the header 'Content-Type'. * * @throws IOException I/O Exception * @throws QueryException query exception */ @Test public void responseWithCharset() throws IOException, QueryException { // Create fake HTTP connection final FakeHttpConnection conn = new FakeHttpConnection(new URL("http://www.test.com")); // Set content type conn.contentType = "text/plain; charset=CP1251"; // set content encoded in CP1251 final String test = "\u0442\u0435\u0441\u0442"; conn.content = Charset.forName("CP1251").encode(test).array(); final ItemList res = new HttpResponse(null, ctx.options).getResponse(conn, true, null); // compare results assertEquals(test, string(res.get(1).string(null))); }
/** * Check if the first X characters of a byte stream match a String. * * @param data The byte array to process * @param pattern The String to match * @return True if the pattern was found, false otherwise */ private static boolean bytesEqualsString(byte[] data, String pattern) { byte[] bytes = new byte[pattern.length()]; Charset csets = Charset.forName("US-ASCII"); boolean fin = false; int currChar = 0; // remove any CR and/or LF characters at the beginning of the article // data while (!fin) { if (currChar >= data.length) break; byte in = data[currChar]; ByteBuffer bb = ByteBuffer.wrap(new byte[] {(byte) in}); CharBuffer cb = csets.decode(bb); char c = cb.charAt(0); if (data.length > 0 && (c == '\n' || c == '\r')) currChar++; else fin = true; if (data.length == 0) fin = true; } // extract bytes (chars) to check from article data for (int i = 0; i < bytes.length && i < data.length; i++, currChar++) { byte in = data[currChar]; bytes[i] = (byte) in; } // decode byte data to characters ByteBuffer bb = ByteBuffer.wrap(bytes); CharBuffer cb = csets.decode(bb); // compare these characters to the pattern String for (int i = 0; i < pattern.length(); i++) if (cb.charAt(i) != pattern.charAt(i)) return false; return true; }
public class AdParser { int level = 0; char saved = 0; private Reader r; boolean body_only = false; private static RuntimeException eof = new RuntimeException("end of stream reached"); public static Charset defaultCharset = Charset.forName("UTF-8"); public static final String SEP = ",;& \n\r"; public static final String EQ = ":="; public static final String OB = "{[(<"; // It's a fish! public static final String CB = "}])>"; public static final String WS = " \t\n\r\b"; // This includes decorator hints for printing. Or will, maybe. For now // it just picks a printer based on the opening bracket. The hint should // be set after at least one object is inserted so we know whether this // ad is a map or list. public static class ParsedAd extends Ad { public AdPrinter printer = AdPrinter.CLASSAD; public AdPrinter setHint(char c) { if (isList()) switch (c) { case '[': return printer = AdPrinter.JSON; case '{': return printer = AdPrinter.CLASSAD; } else switch (c) { case '{': return printer = AdPrinter.JSON; case '[': return printer = AdPrinter.CLASSAD; } return printer; } public String toString() { return printer.toString(this); } } AdParser(CharSequence s, boolean body_only) { this(new StringReader(s.toString()), body_only); } AdParser(InputStream is, boolean body_only) { this(new InputStreamReader(is, defaultCharset), body_only); } AdParser(Reader r, boolean body_only) { this.r = (r instanceof BufferedReader) ? r : new BufferedReader(r); if (this.body_only = body_only) saved = '['; } // Utility methods // --------------- // Get the next character, throwing an unchecked exception on error. private char next() { try { int i = (saved != 0) ? saved : r.read(); saved = 0; if (i <= -1) { if (body_only) return ']'; // Just a little hacky. throw eof; } return (char) i; } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } } // Peek at the next character, then save it. private char peek() { char c = next(); return saved = c; } // Check if a string or range contains a character. private static boolean check(char c, String s) { return s.indexOf(c) >= 0; } private static boolean check(char c, char from, char to) { if (from > to) return check(c, to, from); return c >= from && c <= to; } // Discard characters from the given set. Return the first thing that // isn't part of the ignore set. private char discard() { // Discard whitespace by default. return discard(WS); } private char discard(String s) { char c; for (c = next(); check(c, s); c = next()) ; return c; } // Discard ignored characters as well as comments. private char discardIgnored() { return discardIgnored(WS); } private char discardIgnored(String s) { char c; do switch (c = discard(s)) { case '/': if (peek() != '/') return c; case '#': for (c = peek(); !check(c, "\r\n"); c = next()) ; } while (check(c, s)); return c; } // Ignore all whitespace and check for a character in the given set. // If something else is found, throws a parse error. private char expect(String s) { return expect(s, WS); } private char expect(String s, String i) { char c = discardIgnored(i); if (!check(c, s)) throw new RuntimeException("unexpected character: " + c); return c; } // Lowercase a character assuming it's an A-Z letter. private static char low(char c) { return (char) ((short) c | (short) ' '); } // Parsing methods // --------------- public Ad parse() { try { return parseInto(new ParsedAd()); } catch (RuntimeException e) { if (e == eof) return null; throw e; } } public Ad parseInto(Ad ad) { char open = expect(OB); for (int i = 0; ; i++) { char c = saved = discardIgnored(SEP + WS); // Check for end of ad. if (check(c, CB)) { next(); return ad; } // Discard any extraneous separators or newlines. saved = discardIgnored(SEP + WS); // Read the first token. Object o = readValue(); // Check if it's anonymous or not. // FIXME: These switch cases should not be hardcoded... switch (c = expect(EQ + SEP + CB, " \t\b")) { case ':': // Check for assignment. case '=': // Determine the key. String k = o.toString(); o = findValue(); // Insert into ad as key-value pair. if (o instanceof Atom) ad.putObject(k, ((Atom) o).eval()); else ad.putObject(k, o); if (open > 0 && ad instanceof ParsedAd) ((ParsedAd) ad).setHint(open); open = 0; break; case '}': // Check for end and push char back if found. case ']': case ')': case '>': saved = c; case ',': // Check for separator. case ';': case '&': case ' ': case '\r': case '\n': // Insert into ad as list item. if (o instanceof Atom) ad.putObject(((Atom) o).eval()); else ad.putObject(o); if (open > 0 && ad instanceof ParsedAd) ((ParsedAd) ad).setHint(open); open = 0; } } } // Find and unescape a string. private String readString() { StringBuilder sb = new StringBuilder(); char c = next(); if (c != '"') throw new RuntimeException("expecting start of string"); while (true) switch (c = next()) { case '"': return sb.toString(); case '\\': sb.append(readEscaped()); continue; default: if (Character.isISOControl(c)) throw new RuntimeException("illegal character in string"); sb.append(c); } } // Find an escaped character, assuming the \ has already been read. private char readEscaped() { switch (next()) { case '"': return '"'; case '\\': return '\\'; case '/': return '/'; case 'b': return '\b'; case 'f': return '\f'; case 'n': return '\n'; case 'r': return '\r'; case 't': return '\t'; case 'u': { int r = 0; for (int i = 0; i < 4; i++) { char c = next(); if (check(c, '0', '9')) r = (r << 4) | (c - '0'); else if (check(c = low(c), 'a', 'f')) r = (r << 4) | (c - 'a' + 10); else throw new RuntimeException("illegal escape sequence"); } return (char) r; } } throw new RuntimeException("illegal escape sequence"); } // An atom represents something that can be either an identifier or a // keyword. The string representation of this should be lowercased for // use as a key. private static class Atom { String s; Atom(String s) { this.s = s; } public String toString() { return s.toLowerCase(); } public Object eval() { String sl = s.toLowerCase(); if (sl.equals("false")) return Boolean.FALSE; if (sl.equals("true")) return Boolean.TRUE; if (sl.equals("null")) return null; return s; } } // Try to read an atom. private Atom readAtom() { StringBuilder sb = new StringBuilder(); for (char c = peek(); validAtomPart(c); c = peek()) sb.append(next()); return new Atom(sb.toString()); } // Check if a character can start or be in an atom. private static boolean validAtomStart(char c) { return check(low(c), 'a', 'z') || c == '_'; } private static boolean validAtomPart(char c) { return check(low(c), 'a', 'z') || c == '_' || check(c, '0', '9'); } // Check if a string is a valid identifier. public static boolean checkIdentifier(String s) { for (char i = 0; i < s.length(); i++) { char c = s.charAt(i); if (i == 0 && !validAtomStart(c) || !validAtomPart(c)) return false; } return true; } // Find a value, and return it as a Java object. private Object findValue() { saved = discardIgnored(); return readValue(); } private Object readValue() { char c = peek(); switch (c) { case '"': return readString(); case '-': return readNumber(); } if (check(c, '0', '9')) { return readNumber(); } if (check(c, "{[(<")) { return parseInto(new Ad()); } if (validAtomStart(c)) { return readAtom(); } throw new RuntimeException("cannot parse value starting with: " + c); } private Number readNumber() { char c; boolean d = false; StringBuilder sb = new StringBuilder(); while (true) switch (c = peek()) { case '.': case 'e': case 'E': case '+': d = true; case '-': sb.append(next()); continue; default: if (check(c, '0', '9')) sb.append(next()); else if (check(c, ",:; \n\r\t>}])")) { return d ? new BigDecimal(sb.toString()) : new BigInteger(sb.toString()); } else throw new RuntimeException("unexpected character: " + c); } } }
// 感觉如果没有看过 NIO 的详细内容是不会懂这部分 public class TypeServer extends TCPNIOServer { static String testString = "Thisisateststring"; static class ClientInfo { ByteBuffer inBuf = ByteBuffer.allocateDirect(512); ByteBuffer outBuf = ByteBuffer.allocateDirect(512); boolean outputPending = false; SocketChannel channel; } Map allClients = new HashMap(); Charset encoder = Charset.forName("UTF-8"); protected void handleClient(SelectionKey key) throws IOException { SocketChannel sc = (SocketChannel) key.channel(); ClientInfo ci = (ClientInfo) allClients.get(sc); if (ci == null) throw new IllegalStateException("Unknown client"); if (key.isWritable()) send(sc, ci); if (key.isReadable()) // 从一个客户端读进所有的可用数据 recv(sc, ci); } private void recv(SocketChannel sc, ClientInfo ci) throws IOException { ci.channel.read(ci.inBuf); ByteBuffer tmpBuf = ci.inBuf.duplicate(); tmpBuf.flip(); int bytesProcessed = 0; boolean doneLoop = false; while (!doneLoop) { byte b; try { b = tmpBuf.get(); } catch (BufferUnderflowException bue) { // Processed all data in buffer ci.inBuf.clear(); doneLoop = true; break; } switch (b) { case TypeServerConstants.WELCOME: bytesProcessed++; break; case TypeServerConstants.GET_STRING_REQUEST: bytesProcessed++; if (ci.outputPending) { // Client is backed up. We can't append to // the byte buffer because it's in the wrong // state. We could allocate another buffer // here and change our send method to know // about multiple buffers, but we'll just // assume that the client is dead break; } ci.outBuf.put(TypeServerConstants.GET_STRING_RESPONSE); ByteBuffer strBuf = encoder.encode(testString); ci.outBuf.putShort((short) strBuf.remaining()); ci.outBuf.put(strBuf); ci.outBuf.flip(); send(sc, ci); break; case TypeServerConstants.GET_STRING_RESPONSE: int startPos = tmpBuf.position(); try { int nBytes = tmpBuf.getInt(); byte[] buf = new byte[nBytes]; tmpBuf.get(buf); bytesProcessed += buf.length + 5; String s = new String(buf); // Send the string to the GUI break; } catch (BufferUnderflowException bue) { // Processed all available data ci.inBuf.position(ci.inBuf.position() + bytesProcessed); doneLoop = true; } break; } } } private void send(SocketChannel sc, ClientInfo ci) throws IOException { int len = ci.outBuf.remaining(); int nBytes = sc.write(ci.outBuf); if (nBytes != len) { // Client not ready to receive data ci.outputPending = true; ci.channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); } else { ci.outBuf.clear(); if (ci.outputPending) { ci.outputPending = false; ci.channel.register(selector, SelectionKey.OP_READ); } } } protected void registeredClient(SocketChannel sc) throws IOException { ClientInfo ci = new ClientInfo(); ci.channel = sc; ci.outBuf.clear(); ci.outBuf.put(TypeServerConstants.WELCOME); ci.outBuf.flip(); allClients.put(sc, ci); send(sc, ci); } public static void main(String[] args) throws Exception { TypeServer ts = new TypeServer(); ts.port = Integer.parseInt(args[0]); Thread t = new Thread(ts); t.start(); System.out.println("Type server ready...Type CTRL-D to exit"); while (System.in.read() > 0) ; ts.stopServer(); t.join(); } }
/** * Java client for BaseX. Works with BaseX 7.0 and later * * <p>Documentation: http://docs.basex.org/wiki/Clients * * <p>(C) BaseX Team 2005-12, BSD License */ public class BaseXClient { /** UTF-8 charset. */ static final Charset UTF8 = Charset.forName("UTF-8"); /** Event notifications. */ final Map<String, EventNotifier> notifiers = new HashMap<String, EventNotifier>(); /** Output stream. */ final OutputStream out; /** Socket. */ final Socket socket; /** Cache. */ final BufferedInputStream in; /** Command info. */ String info; /** Socket event reference. */ Socket esocket; /** Socket host name. */ String ehost; /** * Constructor. * * @param host server name * @param port server port * @param user user name * @param pass password * @throws IOException Exception */ public BaseXClient(final String host, final int port, final String user, final String pass) throws IOException { socket = new Socket(); socket.connect(new InetSocketAddress(host, port), 5000); in = new BufferedInputStream(socket.getInputStream()); out = socket.getOutputStream(); ehost = host; // receive timestamp final String ts = receive(); // send {Username}0 and hashed {Password/Timestamp}0 send(user); send(md5(md5(pass) + ts)); // receive success flag if (!ok()) throw new IOException("Access denied."); } /** * Executes a command and serializes the result to an output stream. * * @param cmd command * @param o output stream * @throws IOException Exception */ public void execute(final String cmd, final OutputStream o) throws IOException { // send {Command}0 send(cmd); receive(in, o); info = receive(); if (!ok()) throw new IOException(info); } /** * Executes a command and returns the result. * * @param cmd command * @return result * @throws IOException Exception */ public String execute(final String cmd) throws IOException { final ByteArrayOutputStream os = new ByteArrayOutputStream(); execute(cmd, os); return new String(os.toByteArray(), UTF8); } /** * Creates a query object. * * @param query query string * @return query * @throws IOException Exception */ public Query query(final String query) throws IOException { return new Query(query); } /** * Creates a database. * * @param name name of database * @param input xml input * @throws IOException I/O exception */ public void create(final String name, final InputStream input) throws IOException { send(8, name, input); } /** * Adds a document to a database. * * @param path path to document * @param input xml input * @throws IOException I/O exception */ public void add(final String path, final InputStream input) throws IOException { send(9, path, input); } /** * Replaces a document in a database. * * @param path path to document * @param input xml input * @throws IOException I/O exception */ public void replace(final String path, final InputStream input) throws IOException { send(12, path, input); } /** * Stores a binary resource in a database. * * @param path path to document * @param input xml input * @throws IOException I/O exception */ public void store(final String path, final InputStream input) throws IOException { send(13, path, input); } /** * Watches an event. * * @param name event name * @param notifier event notification * @throws IOException I/O exception */ public void watch(final String name, final EventNotifier notifier) throws IOException { out.write(10); if (esocket == null) { final int eport = Integer.parseInt(receive()); // initialize event socket esocket = new Socket(); esocket.connect(new InetSocketAddress(ehost, eport), 5000); final OutputStream os = esocket.getOutputStream(); receive(in, os); os.write(0); os.flush(); final InputStream is = esocket.getInputStream(); is.read(); listen(is); } send(name); info = receive(); if (!ok()) throw new IOException(info); notifiers.put(name, notifier); } /** * Unwatches an event. * * @param name event name * @throws IOException I/O exception */ public void unwatch(final String name) throws IOException { out.write(11); send(name); info = receive(); if (!ok()) throw new IOException(info); notifiers.remove(name); } /** * Returns command information. * * @return string info */ public String info() { return info; } /** * Closes the session. * * @throws IOException Exception */ public void close() throws IOException { send("exit"); out.flush(); if (esocket != null) esocket.close(); socket.close(); } /** * Checks the next success flag. * * @return value of check * @throws IOException Exception */ boolean ok() throws IOException { out.flush(); return in.read() == 0; } /** * Returns the next received string. * * @return String result or info * @throws IOException I/O exception */ String receive() throws IOException { final ByteArrayOutputStream os = new ByteArrayOutputStream(); receive(in, os); return new String(os.toByteArray(), UTF8); } /** * Sends a string to the server. * * @param s string to be sent * @throws IOException I/O exception */ void send(final String s) throws IOException { out.write((s + '\0').getBytes(UTF8)); } /** * Receives a string and writes it to the specified output stream. * * @param is input stream * @param os output stream * @throws IOException I/O exception */ static void receive(final InputStream is, final OutputStream os) throws IOException { for (int b; (b = is.read()) > 0; ) { // read next byte if 0xFF is received os.write(b == 0xFF ? is.read() : b); } } /** * Sends a command, argument, and input. * * @param cmd command * @param path path to document * @param input xml input * @throws IOException I/O exception */ private void send(final int cmd, final String path, final InputStream input) throws IOException { out.write(cmd); send(path); send(input); } /** * Starts the listener thread. * * @param is input stream */ private void listen(final InputStream is) { final BufferedInputStream bi = new BufferedInputStream(is); new Thread() { @Override public void run() { try { while (true) { ByteArrayOutputStream os = new ByteArrayOutputStream(); receive(bi, os); final String name = new String(os.toByteArray(), UTF8); os = new ByteArrayOutputStream(); receive(bi, os); final String data = new String(os.toByteArray(), UTF8); notifiers.get(name).notify(data); } } catch (final IOException ex) { // loop will be quit if no data can be received anymore } } }.start(); } /** * Sends an input stream to the server. * * @param input xml input * @throws IOException I/O exception */ private void send(final InputStream input) throws IOException { final BufferedInputStream bis = new BufferedInputStream(input); final BufferedOutputStream bos = new BufferedOutputStream(out); for (int b; (b = bis.read()) != -1; ) { // 0x00 and 0xFF will be prefixed by 0xFF if (b == 0x00 || b == 0xFF) bos.write(0xFF); bos.write(b); } bos.write(0); bos.flush(); info = receive(); if (!ok()) throw new IOException(info); } /** * Returns an MD5 hash. * * @param pw String * @return String */ private static String md5(final String pw) { final StringBuilder sb = new StringBuilder(); try { final MessageDigest md = MessageDigest.getInstance("MD5"); md.update(pw.getBytes()); for (final byte b : md.digest()) { final String s = Integer.toHexString(b & 0xFF); if (s.length() == 1) sb.append('0'); sb.append(s); } } catch (final NoSuchAlgorithmException ex) { // should not occur ex.printStackTrace(); } return sb.toString(); } /** Inner class for iterative query execution. */ public class Query { /** Query id. */ private final String id; /** Cached results. */ private ArrayList<byte[]> cache; /** Cache pointer. */ private int pos; /** * Standard constructor. * * @param query query string * @throws IOException I/O exception */ public Query(final String query) throws IOException { id = exec(0, query); } /** * Binds a value to an external variable. * * @param name name of variable * @param value value * @throws IOException I/O exception */ public void bind(final String name, final String value) throws IOException { bind(name, value, ""); } /** * Binds a value with the specified type to an external variable. * * @param name name of variable * @param value value * @param type type (can be an empty string) * @throws IOException I/O exception */ public void bind(final String name, final String value, final String type) throws IOException { cache = null; exec(3, id + '\0' + name + '\0' + value + '\0' + type); } /** * Binds a value to the context item. * * @param value value * @throws IOException I/O exception */ public void context(final String value) throws IOException { context(value, ""); } /** * Binds a value with the specified type to the context item. * * @param value value * @param type type (can be an empty string) * @throws IOException I/O exception */ public void context(final String value, final String type) throws IOException { cache = null; exec(14, id + '\0' + value + '\0' + type); } /** * Checks for the next item. * * @return result of check * @throws IOException I/O exception */ public boolean more() throws IOException { if (cache == null) { out.write(4); send(id); cache = new ArrayList<byte[]>(); final ByteArrayOutputStream os = new ByteArrayOutputStream(); while (in.read() > 0) { receive(in, os); cache.add(os.toByteArray()); os.reset(); } if (!ok()) throw new IOException(receive()); pos = 0; } if (pos < cache.size()) return true; cache = null; return false; } /** * Returns the next item. * * @return item string * @throws IOException I/O Exception */ public String next() throws IOException { return more() ? new String(cache.set(pos++, null), UTF8) : null; } /** * Returns the whole result of the query. * * @return query result * @throws IOException I/O Exception */ public String execute() throws IOException { return exec(5, id); } /** * Returns query info in a string. * * @return query info * @throws IOException I/O exception */ public String info() throws IOException { return exec(6, id); } /** * Returns serialization parameters in a string. * * @return query info * @throws IOException I/O exception */ public String options() throws IOException { return exec(7, id); } /** * Closes the query. * * @throws IOException I/O exception */ public void close() throws IOException { exec(2, id); } /** * Executes the specified command. * * @param cmd command * @param arg argument * @return resulting string * @throws IOException I/O exception */ private String exec(final int cmd, final String arg) throws IOException { out.write(cmd); send(arg); final String s = receive(); if (!ok()) throw new IOException(receive()); return s; } } /** Interface for event notifications. */ public interface EventNotifier { /** * Invoked when a database event was fired. * * @param value event string */ void notify(final String value); } }