package com.sun.slp;
import java.util.*;
import java.io.*;
class SLPV1SSrvMsg extends SSrvMsg {
final static char SPACE = ' ';
final static char COMMA = ',';
final static char OR_OP = '|';
final static char AND_OP = '&';
final static char HASH = '#';
final static char EQUAL_OP = '=';
final static char NOT_OP = '!';
final static char LESS_OP = '<';
final static char GREATER_OP = '>';
final static char GEQUAL_OP = 'g';
final static char LEQUAL_OP = 'l';
final static char OPEN_PAREN = '(';
final static char CLOSE_PAREN = ')';
final static char PRESENT = '*';
final static String WILDCARD = "*";
String charCode = IANACharCode.UTF8;
protected SLPV1SSrvMsg() {}
SLPV1SSrvMsg(SrvLocHeader hdr, DataInputStream dis)
throws ServiceLocationException, IOException {
super(hdr, dis);
}
static SrvLocMsg makeEmptyReply(SLPHeaderV1 hdr)
throws ServiceLocationException {
SLPV1SSrvMsg msg = new SLPV1SSrvMsg();
msg.hdr = hdr;
msg.makeReply(new Hashtable(), null);
return msg;
}
void initialize(DataInputStream dis)
throws ServiceLocationException, IOException {
SLPHeaderV1 hdr = (SLPHeaderV1)getHeader();
StringBuffer buf = new StringBuffer();
hdr.parsePreviousRespondersIn(dis);
hdr.getString(buf, dis);
String rq = buf.toString();
StringTokenizer st = new StringTokenizer(rq, "/", true);
try {
String type =
Defaults.SERVICE_PREFIX + ":" +
st.nextToken().trim().toLowerCase() + ":";
serviceType =
hdr.checkServiceType(type);
st.nextToken();
String scope = st.nextToken().trim().toLowerCase();
if (scope.equals("/")) {
scope = "";
} else {
st.nextToken();
if (scope.length() > 0) {
hdr.validateScope(scope);
}
}
hdr.scopes = new Vector();
if (scope.length() <= 0) {
scope = Defaults.DEFAULT_SCOPE;
}
hdr.scopes.addElement(scope.toLowerCase().trim());
String q = "";
while (st.hasMoreTokens()) {
q = q + st.nextToken();
}
if (!q.endsWith("/")) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {rq});
}
query = q.substring(0, q.length()-1);
charCode = hdr.charCode;
convertQuery();
if (serviceType.equals(Defaults.DA_SERVICE_TYPE.toString())) {
hdr.mcast = true;
}
hdr.constructDescription("SrvRqst",
" service type=``" +
serviceType + "''\n" +
" query=``" +
query + "''");
} catch (NoSuchElementException ex) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {rq});
}
}
SrvLocMsg makeReply(Hashtable urltable,
Hashtable URLSignatures)
throws ServiceLocationException {
SLPHeaderV1 hdr =
((SLPHeaderV1)getHeader()).makeReplyHeader();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Enumeration en = urltable.keys();
Vector urls = new Vector();
while (en.hasMoreElements()) {
ServiceURL surl = (ServiceURL)en.nextElement();
ServiceType type = surl.getServiceType();
if (!type.isAbstractType() && type.isServiceURL()) {
urls.addElement(surl);
}
}
hdr.iNumReplies = urls.size();
int n = urls.size();
hdr.putInt(n, baos);
en = urls.elements();
while (en.hasMoreElements()) {
ServiceURL surl = (ServiceURL)en.nextElement();
hdr.parseServiceURLOut(surl, true, baos);
}
hdr.payload = baos.toByteArray();
hdr.constructDescription("SrvRply",
" service URLs=``" + urls + "''\n");
return hdr;
}
void convertQuery()
throws ServiceLocationException {
query = query.trim();
if (query.length() <= 0) {
return;
}
if (!(query.startsWith("(") && query.endsWith(")"))) {
query = rewriteQueryJoin(query);
}
query = rewriteQuery(query);
}
private String rewriteQueryJoin(String query)
throws ServiceLocationException {
StringBuffer sbuf = new StringBuffer();
StringTokenizer tk = new StringTokenizer(query, ",", true);
boolean lastTokComma = true;
int numEx = 0;
while (tk.hasMoreElements()) {
String exp = tk.nextToken().trim();
if (exp.equals(",")) {
if (lastTokComma) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
} else {
lastTokComma = true;
}
} else {
lastTokComma = false;
if (exp.length() <= 0) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
}
sbuf.append("(");
sbuf.append(exp);
sbuf.append(")");
numEx++;
}
}
if (lastTokComma || numEx == 0) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
}
if (numEx > 1) {
sbuf.insert(0, "(&");
sbuf.append(")");
}
return sbuf.toString();
}
private String rewriteQuery(String whereList)
throws ServiceLocationException {
StreamTokenizer tk =
new StreamTokenizer(new StringReader(whereList));
tk.resetSyntax();
tk.whitespaceChars('\000','\037');
tk.ordinaryChar(SPACE);
tk.wordChars('!', '%');
tk.ordinaryChar(AND_OP);
tk.wordChars('\'', '\'');
tk.ordinaryChar(OPEN_PAREN);
tk.ordinaryChar(CLOSE_PAREN);
tk.wordChars('*', '{');
tk.ordinaryChar(OR_OP);
tk.wordChars('}', '~');
tk.ordinaryChar(EQUAL_OP);
tk.ordinaryChar(NOT_OP);
tk.ordinaryChar(LESS_OP);
tk.ordinaryChar(GREATER_OP);
StringBuffer buf = new StringBuffer();
try {
parseInternal(tk, buf, true);
} catch (IOException ex) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
}
return buf.toString();
}
private void
parseInternal(StreamTokenizer tk, StringBuffer buf, boolean start)
throws ServiceLocationException, IOException {
int tok = 0;
boolean ret = true;
do {
tok = eatWhite(tk);
if (tok == OPEN_PAREN) {
tok = eatWhite(tk);
int logOp = tok;
if (logOp == AND_OP) {
tok = tk.nextToken();
String str = tk.sval;
tk.pushBack();
if (tok == StreamTokenizer.TT_WORD) {
if (str.charAt(0) != HASH) {
parseLogicalExpression(logOp, tk, buf);
} else {
parse(tk, buf, true);
}
} else {
parseLogicalExpression(logOp, tk, buf);
}
break;
} else if (logOp == OR_OP) {
parseLogicalExpression(logOp, tk, buf);
break;
} else {
tk.pushBack();
parse(tk, buf, false);
break;
}
} else {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
}
} while (true);
if (start) {
tok = eatWhite(tk);
if (tok != StreamTokenizer.TT_EOF) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
}
}
}
private void
parseLogicalExpression(int logOp, StreamTokenizer tk, StringBuffer buf)
throws ServiceLocationException, IOException {
buf.append((char)OPEN_PAREN);
buf.append((char)logOp);
int tok = 0;
do {
tok = eatWhite(tk);
if (tok == OPEN_PAREN) {
tk.pushBack();
parseInternal(tk, buf, false);
} else if (tok == CLOSE_PAREN) {
buf.append((char)tok);
return;
} else {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
}
} while (tok != StreamTokenizer.TT_EOF);
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
}
private void parse(StreamTokenizer tk,
StringBuffer buf,
boolean firstEscaped)
throws ServiceLocationException, IOException {
String tag = "";
int tok = 0;
tok = eatWhite(tk);
if (tok != StreamTokenizer.TT_WORD) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
}
tag = parseTag(tk, firstEscaped);
if (tag.length() <= 0) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
}
tag = ServiceLocationAttributeV1.unescapeAttributeString(tag,
charCode);
tag = ServiceLocationAttribute.escapeAttributeString(tag, true);
char compOp = parseOperator(tk);
if (compOp == PRESENT) {
buf.append(OPEN_PAREN);
buf.append(tag);
buf.append(EQUAL_OP);
buf.append(PRESENT);
buf.append(CLOSE_PAREN);
return;
}
String valTok = parseValue(tk);
if (compOp == NOT_OP) {
try {
int n = Integer.parseInt(valTok);
if (n < Integer.MAX_VALUE) {
buf.append(OPEN_PAREN);
buf.append(tag);
buf.append(GREATER_OP);
buf.append(EQUAL_OP);
buf.append(n + 1);
buf.append(CLOSE_PAREN);
}
if (n > Integer.MIN_VALUE) {
buf.append(OPEN_PAREN);
buf.append(tag);
buf.append(LESS_OP);
buf.append(EQUAL_OP);
buf.append(n - 1);
buf.append(CLOSE_PAREN);
}
if ((n < Integer.MAX_VALUE) && (n > Integer.MIN_VALUE)) {
buf.insert(0, OR_OP);
buf.insert(0, OPEN_PAREN);
buf.append(CLOSE_PAREN);
}
} catch (NumberFormatException ex) {
buf.append(OPEN_PAREN);
buf.append(AND_OP);
buf.append(OPEN_PAREN);
buf.append(tag);
buf.append(EQUAL_OP);
buf.append(PRESENT);
buf.append(CLOSE_PAREN);
buf.append(OPEN_PAREN);
buf.append(NOT_OP);
buf.append(OPEN_PAREN);
buf.append(tag);
buf.append(EQUAL_OP);
buf.append(valTok);
buf.append(CLOSE_PAREN);
buf.append(CLOSE_PAREN);
buf.append(CLOSE_PAREN);
}
} else if ((compOp == LESS_OP) || (compOp == GREATER_OP)) {
int n = 0;
try {
n = Integer.parseInt(valTok);
} catch (NumberFormatException ex) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
}
if ((n == Integer.MAX_VALUE) || (n == Integer.MIN_VALUE)) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
}
buf.append(OPEN_PAREN);
buf.append(tag);
if (compOp == LESS_OP) {
buf.append(LESS_OP);
buf.append(EQUAL_OP);
buf.append(n - 1);
} else {
buf.append(GREATER_OP);
buf.append(EQUAL_OP);
buf.append(n + 1);
}
buf.append(CLOSE_PAREN);
} else {
buf.append(OPEN_PAREN);
buf.append(tag);
if (compOp == LEQUAL_OP) {
buf.append(LESS_OP);
buf.append(EQUAL_OP);
} else if (compOp == GEQUAL_OP) {
buf.append(GREATER_OP);
buf.append(EQUAL_OP);
} else {
buf.append(compOp);
}
buf.append(valTok);
buf.append(CLOSE_PAREN);
}
}
private String parseTag(StreamTokenizer tk, boolean ampStart)
throws ServiceLocationException, IOException {
String value = "";
if (ampStart) {
value = value +"&";
ampStart = false;
}
do {
if (tk.ttype == StreamTokenizer.TT_WORD) {
value += tk.sval;
} else if ((char)tk.ttype == SPACE) {
value = value + " ";
} else if ((char)tk.ttype == AND_OP) {
value = value + "&";
} else {
break;
}
tk.nextToken();
} while (true);
return value.trim();
}
private char parseOperator(StreamTokenizer tk)
throws ServiceLocationException, IOException {
int tok = tk.ttype;
if ((char)tok == CLOSE_PAREN) {
return PRESENT;
}
if (tok != EQUAL_OP && tok != NOT_OP &&
tok != LESS_OP && tok != GREATER_OP) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
}
char compOp = (char)tok;
tok = tk.nextToken();
if ((char)tok == EQUAL_OP) {
if (compOp != LESS_OP && compOp != GREATER_OP &&
compOp != EQUAL_OP && compOp != NOT_OP) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
}
if (compOp == LESS_OP) {
compOp = LEQUAL_OP;
} else if (compOp == GREATER_OP) {
compOp = GEQUAL_OP;
}
} else if (compOp != LESS_OP && compOp != GREATER_OP) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
} else {
tk.pushBack();
}
return compOp;
}
private String parseValue(StreamTokenizer tk)
throws ServiceLocationException, IOException {
int tok = 0;
StringBuffer valTok = new StringBuffer();
tok = eatWhite(tk);
if ((char)tok == OPEN_PAREN) {
valTok.append("(");
do {
tok = tk.nextToken();
if ((char)tok == CLOSE_PAREN) {
valTok.append(")");
break;
} else if ((char)tok == EQUAL_OP) {
valTok.append("=");
} else if (tok == StreamTokenizer.TT_WORD) {
valTok.append(tk.sval);
} else {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
}
} while (true);
tok = eatWhite(tk);
if ((char)tok != CLOSE_PAREN) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
}
} else {
if (tok == CLOSE_PAREN) {
throw
new ServiceLocationException(
ServiceLocationException.PARSE_ERROR,
"v1_query_error",
new Object[] {query});
}
do {
if (tok == StreamTokenizer.TT_WORD) {
valTok.append(tk.sval);
} else if ((tok != StreamTokenizer.TT_EOF) &&
(tok != StreamTokenizer.TT_EOL) &&
(tok != CLOSE_PAREN)) {
valTok.append((char)tok);
}
tok = tk.nextToken();
} while (tok != CLOSE_PAREN);
}
String strval = valTok.toString().trim();
boolean wildstart = false;
boolean wildend = false;
if (strval.startsWith(WILDCARD)) {
wildstart = true;
strval = strval.substring(1, strval.length());
}
if (strval.endsWith(WILDCARD)) {
wildend = true;
strval = strval.substring(0, strval.length()-1);
}
Object val =
ServiceLocationAttributeV1.evaluate(strval, charCode);
if (val instanceof String) {
strval =
ServiceLocationAttribute.escapeAttributeString(val.toString(),
false);
if (wildstart) {
strval = WILDCARD + strval;
}
if (wildend) {
strval = strval + WILDCARD;
}
} else {
strval = val.toString();
}
return strval;
}
private int eatWhite(StreamTokenizer tk)
throws IOException {
int tok = tk.nextToken();
while (tok == SPACE) {
tok = tk.nextToken();
}
return tok;
}
}