|
View:
New views
5 Messages
—
Rating Filter:
Alert me
|
|
|
ruby client stompconnect weblogic 9.2 issueGreetings,
First, I'd like to say thank-you very much for StompConnect. However, I've run into a small problem with the Ruby client and WebLogic 9.2. The Ruby client has a content-type header in the SEND frame. I think StompConnect attempts to forward this header to JMS. The error message I'm seeing is: ERROR message:[JMSClientExceptions:055121]Invalid property name, "content-type" weblogic.jms.common.MessageFormatException: [JMSClientExceptions:055121]Invalid property name, "content-type" at weblogic.jms.common.MessageImpl.setObjectProperty(MessageImpl.java:1353) at org.codehaus.stomp.jms.StompSession.copyStandardHeadersFromFrameToMessag e(StompSession.java:234) Please advise. Thanks, Charlie.Sadler<AT />mathworks.com --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
Re: ruby client stompconnect weblogic 9.2 issueHey Charlie,
Yeah, that is going to be a problem. The only header explictly removed is content-length, not content-type, the copyStandardHeadersFromFrameToMessage method translates a few stomp headers to JMS equivalents, then copies the rest into the JMS headers - including content-type if it is there. If weblogic is validating via a whitelist for acceptable headers (as it seems to be), some/any other stomp header that gets copied into the message will be a problem - i.e. content-length gets removed, but other headers won't be, and they could cause a problem as well - perhaps there needs to be a cofigurable list of acceptable headers to filter against? (I smell a new feature...) Anyway, below is what I am 90% sure is the code of interest, if you can't fix it/figure it out, and James doesn't get back to you, I'll give it a whirl (I am so booked right now) - I used to do lots of weblogic work before I caught the rails bug :) Below is the code of interest, I am 90% sure this is all that needs to be altered... https://svn.codehaus.org/stomp/trunk/stompconnect/src/main/java/org/codehaus/stomp/jms/StompSession.java <pre> protected void copyStandardHeadersFromFrameToMessage(StompFrame command, Message msg) throws JMSException, ProtocolException { final Map headers = new HashMap(command.getHeaders()); // the standard JMS headers msg.setJMSCorrelationID((String) headers.remove(Stomp.Headers.Send.CORRELATION_ID)); Object o = headers.remove(Stomp.Headers.Send.TYPE); if (o != null) { msg.setJMSType((String) o); } o = headers.remove(Stomp.Headers.Send.REPLY_TO); if (o != null) { msg.setJMSReplyTo(convertDestination((String) o)); } // now the general headers for (Iterator iter = headers.entrySet().iterator(); iter.hasNext();) { Map.Entry entry = (Map.Entry) iter.next(); String name = (String) entry.getKey(); Object value = entry.getValue(); msg.setObjectProperty(name, value); } } protected Message convertFrame(StompFrame command) throws JMSException, ProtocolException { final Map headers = command.getHeaders(); final Message msg; if (headers.containsKey(Stomp.Headers.CONTENT_LENGTH)) { headers.remove(Stomp.Headers.CONTENT_LENGTH); BytesMessage bm = session.createBytesMessage(); bm.writeBytes(command.getContent()); msg = bm; } else { String text; try { text = new String(command.getContent(), "UTF-8"); } catch (Throwable e) { throw new ProtocolException("Text could not bet set: " + e, false, e); } msg = session.createTextMessage(text); } copyStandardHeadersFromFrameToMessage(command, msg); return msg; } </pre>
|
|
|
RE: ruby client stompconnect weblogic 9.2 issueHi Andrew,
Thanks for the response. It seems like content-type is the only auto-generated header from the Ruby client I'm having an issue with. All the other auto-headers which make it to copyStandardHeadersFromFrameToMessage for the SEND command seem to be ok by WebLogic. I'll make a local code change to keep my project rolling. On a related note, I'm wondering if I might leverage content-type within org.codehaus.stomp.jms.StompSession.convertFrame to determine whether or not to createBytesMessage or createTextMessage? It seems like the Ruby client always sends the content-length header. Thanks, Charlie -----Original Message----- From: andrewk [mailto:andrew@...] Sent: Wednesday, April 04, 2007 10:08 AM To: dev@... Subject: Re: [stomp-dev] ruby client stompconnect weblogic 9.2 issue Hey Charlie, Yeah, that is going to be a problem. The only header explictly removed is content-length, not content-type, the copyStandardHeadersFromFrameToMessage method translates a few stomp headers to JMS equivalents, then copies the rest into the JMS headers - including content-type if it is there. If weblogic is validating via a whitelist for acceptable headers (as it seems to be), some/any other stomp header that gets copied into the message will be a problem - i.e. content-length gets removed, but other headers won't be, and they could cause a problem as well - perhaps there needs to be a cofigurable list of acceptable headers to filter against? (I smell a new feature...) Anyway, below is what I am 90% sure is the code of interest, if you can't fix it/figure it out, and James doesn't get back to you, I'll give it a whirl (I am so booked right now) - I used to do lots of weblogic work before I caught the rails bug :) Below is the code of interest, I am 90% sure this is all that needs to be altered... https://svn.codehaus.org/stomp/trunk/stompconnect/src/main/java/org/code haus/stomp/jms/StompSession.java <pre> protected void copyStandardHeadersFromFrameToMessage(StompFrame command, Message msg) throws JMSException, ProtocolException { final Map headers = new HashMap(command.getHeaders()); // the standard JMS headers msg.setJMSCorrelationID((String) headers.remove(Stomp.Headers.Send.CORRELATION_ID)); Object o = headers.remove(Stomp.Headers.Send.TYPE); if (o != null) { msg.setJMSType((String) o); } o = headers.remove(Stomp.Headers.Send.REPLY_TO); if (o != null) { msg.setJMSReplyTo(convertDestination((String) o)); } // now the general headers for (Iterator iter = headers.entrySet().iterator(); iter.hasNext();) { Map.Entry entry = (Map.Entry) iter.next(); String name = (String) entry.getKey(); Object value = entry.getValue(); msg.setObjectProperty(name, value); } } protected Message convertFrame(StompFrame command) throws JMSException, ProtocolException { final Map headers = command.getHeaders(); final Message msg; if (headers.containsKey(Stomp.Headers.CONTENT_LENGTH)) { headers.remove(Stomp.Headers.CONTENT_LENGTH); BytesMessage bm = session.createBytesMessage(); bm.writeBytes(command.getContent()); msg = bm; } else { String text; try { text = new String(command.getContent(), "UTF-8"); } catch (Throwable e) { throw new ProtocolException("Text could not bet set: " + e, false, e); } msg = session.createTextMessage(text); } copyStandardHeadersFromFrameToMessage(command, msg); return msg; } </pre> Charlie Sadler wrote: > > Greetings, > > First, I'd like to say thank-you very much for StompConnect. However, > I've run into a small problem with the Ruby client and WebLogic 9.2. The > Ruby client has a content-type header in the SEND frame. I think > StompConnect attempts to forward this header to JMS. The error message > I'm seeing is: > > ERROR > message:[JMSClientExceptions:055121]Invalid property name, > "content-type" > weblogic.jms.common.MessageFormatException: > [JMSClientExceptions:055121]Invalid property name, "content-type" > at > > at > org.codehaus.stomp.jms.StompSession.copyStandardHeadersFromFrameToMessag > e(StompSession.java:234) > > Please advise. > > Thanks, > Charlie.Sadler<AT />mathworks.com > > --------------------------------------------------------------------- > To unsubscribe from this list please visit: > > http://xircles.codehaus.org/manage_email > > > -- View this message in context: http://www.nabble.com/ruby-client-stompconnect-weblogic-9.2-issue-tf3522 646.html#a9837648 Sent from the stomp - dev mailing list archive at Nabble.com. --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
|
|
RE: ruby client stompconnect weblogic 9.2 issueHey Charlie, glad you got past that -
There has been discussion about this exact before - and I know someone offered up a version of the stomp ruby gem that does not set the content-length (or doesn't all the time anyway). Personally, I just get back the jms bytes message and have a simple method to get the text from it, so I guess I just worked around this instead of trying to change it - but that's me. As for using content-type - this is not a standard header in the STOMP protocol, but content-length is. To be honest there are very few official stomp headers, but content-length is one of them, which may be why it was used/overloaded by the stomp -> JMS translation code as the indicator of JMS message type to create. As I said, this has been discussed before, so if you look back you can read about some of the thinking for yourself, I don't remember the details. For you it may work very well between the ruby gem and StompConnect to use content-type, but unless the stomp standard is changed to include this as a standard but optional header, I wouldn't expect it to be added to StompConnect...just my opinion, I don't make no rules around here :) It seems like this is a problem that should maybe be considered again though. Would it be a bad thing to add content-type to the stomp standard, accepting the usual suspects (i.e. mime-type values)? Or, as sTomp is about sending Text, wouldn't creating a jms TextMessage be a more obvious 'default'? I don't know, just thinking about it. So use content-type in your code if you want to, my suggestion in the short term is to suck it up and read the bytes messages, or tweak the ruby code via a monkeypatch to not send the content length. I like working code better than pithy suggestions, so here's how I would do it. Java message reader (I stole this from someone, I don't remember who, then tweaked it a bit): private String getMessageText(Message m) throws JMSException { String result = ""; if (m instanceof BytesMessage) { BytesMessage bytMsg = (BytesMessage) m; StringBuffer msg = new StringBuffer(); int c; try { while ((c=bytMsg.readByte()) != -1) { msg.append((char) c); } } catch (javax.jms.MessageEOFException e) { log.debug("end of message exception."); } log.debug("Received BytesMessage: " + msg); result = msg.toString(); } else if (m instanceof TextMessage){ TextMessage txtMsg = (TextMessage) m; log.debug("Received: TextMessage" + txtMsg.getText()); result = txtMsg.getText(); } else { log.error("Unexpected Message Type: " + m); } return result; } Ruby monkey-patch option - really not tested, but something obvious like this would work: Stomp::Connection.class_eval do def _transmit(s, command, headers={}, body='') @transmit_semaphore.synchronize do s.puts command headers.each {|k,v| s.puts "#{k}:#{v}" } s.puts "content-length: #{body.length}" # s.puts "content-type: text/plain; charset=UTF-8" s.puts s.write body s.write "\0" end end end -Andrew Kuklewicz
|
|
|
RE: ruby client stompconnect weblogic 9.2 issueHi Andrew,
I thought the issue with setting the content-type property on the JMS message might be a protocol conflict. Not so, simply, a dash is an illegal character for a property name. From: Java Message Service, Version 1.1, April 12, 2002 3.5.1 Property Names Property names must obey the rules for a message selector identifier. See Section 3.8.1.1, "Message Selector Syntax," for more information. 3.8.1.1 Message Selector Syntax * Identifiers: - An identifier is an unlimited-length character sequence that must begin with a Java identifier start character; all following characters must be Java identifier part characters. An identifier start character is any character for which the method Character.isJavaIdentifierStart returns true. This includes '_' and '$'. An identifier part character is any character for which the method Character.isJavaIdentifierPart returns true. My fix was to modify org.codehaus.stomp.jms.StompSession.copyStandardHeadersFromFrameToMessag e to translate illegal characters to underlines for all setObjectProperty name arguments. I don't know if this is an issue for other JMS implementations and StompConnect. My only experience is with WebLogic 9.2 and StompConnect. The one line change and surrounding lines are: // now the general headers for (Iterator iter = headers.entrySet().iterator(); iter.hasNext(); ) { Map.Entry entry = (Map.Entry) iter.next(); String name = (String) entry.getKey(); name = convertPropertyName(name); // transform illegal characters Object value = entry.getValue(); msg.setObjectProperty(name, value); } The new convertPropertyName method is: protected String convertPropertyName(String propertyName) { if (null == propertyName) { return null; } final char goodChar = '_'; final StringBuffer buf = new StringBuffer(propertyName); for (int i = 0; i < buf.length(); i++) { if ((0 == i) && (!Character.isJavaIdentifierStart(buf.charAt(i)))) { buf.setCharAt(i, goodChar); } else if (!Character.isJavaIdentifierPart(buf.charAt(i))) { buf.setCharAt(i, goodChar); } } return buf.toString(); } FWIW, my thought on using the content-type to determine bytes or text message is: if it's there, might as well use it. Maybe the Ruby STOMP client people put the content-type header in for a good reason. Maybe content-type is useful to ActiveMQ. I'm guessing the Ruby STOMP client people aren't going to remove the header anytime soon. Anyway, the code modifications below follow the current behavior when the content-type header is missing - when the content-length header is present then, send a bytes message else, send a text message. Add Stomp.Headers.CONTENT_TYPE... public interface Headers { String SEPERATOR = ":"; String RECEIPT_REQUESTED = "receipt"; String TRANSACTION = "transaction"; String CONTENT_LENGTH = "content-length"; String CONTENT_TYPE = "content-type"; Modify org.codehaus.stomp.jms.StompSession... Change... import java.io.IOException; To import java.io.*; Add... import javax.mail.internet.*; import java.nio.charset.*; Change method convertFrame to... protected Message convertFrame(StompFrame command) throws JMSException, ProtocolException { final Map headers = command.getHeaders(); final Message msg; Charset charset = getCharset(headers); if (null == charset) { msg = session.createBytesMessage(); ( (BytesMessage) msg).writeBytes(command.getContent()); } else { try { String text = new String(command.getContent(), charset.name()); msg = session.createTextMessage(text); } catch (UnsupportedEncodingException ex) { throw new ProtocolException("Text could not be set: " + ex, false, ex); } } copyStandardHeadersFromFrameToMessage(command, msg); return msg; } Add method getCharset... protected Charset getCharset(Map headers) throws ProtocolException { // determine text character set or null for byte message final Charset charset; final String defaultCharsetName = "UTF-8"; if (headers.containsKey(Stomp.Headers.CONTENT_TYPE)) { final ContentType contentType; try { contentType = new ContentType( (String) headers.get(Stomp.Headers.CONTENT_TYPE)); } catch (ParseException ex) { throw new ProtocolException( "Cannot parse " + Stomp.Headers.CONTENT_TYPE + " header: " + ex, false, ex); } if (contentType.match("text/*")) { String csname = contentType.getParameter("charset"); if (null == csname) { csname = defaultCharsetName; } charset = Charset.forName(csname); } else { charset = null; } } else if (headers.containsKey(Stomp.Headers.CONTENT_LENGTH)) { charset = null; } else { charset = Charset.forName(defaultCharsetName); } headers.remove(Stomp.Headers.CONTENT_LENGTH); return charset; } Thanks, Charlie --------------------------------------------------------------------- To unsubscribe from this list please visit: http://xircles.codehaus.org/manage_email |
| Free embeddable forum powered by Nabble | Forum Help |