http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingInboundTransformer.java ---------------------------------------------------------------------- diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingInboundTransformer.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingInboundTransformer.java new file mode 100644 index 0000000..82c03c6 --- /dev/null +++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingInboundTransformer.java @@ -0,0 +1,102 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.proton.jms; + +import org.apache.qpid.proton.amqp.Binary; +import org.apache.qpid.proton.amqp.messaging.Section; +import org.apache.qpid.proton.amqp.messaging.*; + +import javax.jms.*; +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** +* @author <a href="http://hiramchirino.com">Hiram Chirino</a> +*/ +public class JMSMappingInboundTransformer extends InboundTransformer { + + public JMSMappingInboundTransformer(JMSVendor vendor) { + super(vendor); + } + + @Override + public Message transform(EncodedMessage amqpMessage) throws Exception { + org.apache.qpid.proton.message.Message amqp = amqpMessage.decode(); + + Message rc; + final Section body = amqp.getBody(); + if( body == null ) { + rc = vendor.createMessage(); + } else if( body instanceof Data ) { + Binary d = ((Data) body).getValue(); + BytesMessage m = vendor.createBytesMessage(); + m.writeBytes(d.getArray(), d.getArrayOffset(), d.getLength()); + rc = m; + } else if (body instanceof AmqpSequence ) { + AmqpSequence sequence = (AmqpSequence) body; + StreamMessage m = vendor.createStreamMessage(); + for( Object item : sequence.getValue()) { + m.writeObject(item); + } + rc = m; + } else if (body instanceof AmqpValue) { + Object value = ((AmqpValue) body).getValue(); + if( value == null ) { + rc = vendor.createObjectMessage(); + } if( value instanceof String ) { + TextMessage m = vendor.createTextMessage(); + m.setText((String) value); + rc = m; + } else if( value instanceof Binary ) { + Binary d = (Binary) value; + BytesMessage m = vendor.createBytesMessage(); + m.writeBytes(d.getArray(), d.getArrayOffset(), d.getLength()); + rc = m; + } else if( value instanceof List) { + StreamMessage m = vendor.createStreamMessage(); + for( Object item : (List) value) { + m.writeObject(item); + } + rc = m; + } else if( value instanceof Map) { + MapMessage m = vendor.createMapMessage(); + final Set<Map.Entry<String, Object>> set = ((Map) value).entrySet(); + for (Map.Entry<String, Object> entry : set) { + m.setObject(entry.getKey(), entry.getValue()); + } + rc = m; + } else { + ObjectMessage m = vendor.createObjectMessage(); + m.setObject((Serializable) value); + rc = m; + } + } else { + throw new RuntimeException("Unexpected body type: "+body.getClass()); + } + rc.setJMSDeliveryMode(defaultDeliveryMode); + rc.setJMSPriority(defaultPriority); + rc.setJMSExpiration(defaultTtl); + + populateMessage(rc, amqp); + + rc.setLongProperty(prefixVendor + "MESSAGE_FORMAT", amqpMessage.getMessageFormat()); + rc.setBooleanProperty(prefixVendor + "NATIVE", false); + return rc; + } +}
http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java ---------------------------------------------------------------------- diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java new file mode 100644 index 0000000..47c487c --- /dev/null +++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java @@ -0,0 +1,246 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.proton.jms; + +import org.apache.qpid.proton.amqp.messaging.Section; +import org.apache.qpid.proton.codec.CompositeWritableBuffer; +import org.apache.qpid.proton.codec.WritableBuffer; +import org.apache.qpid.proton.codec.DroppingWritableBuffer; +import org.apache.qpid.proton.message.ProtonJMessage; +import org.apache.qpid.proton.amqp.Binary; +import org.apache.qpid.proton.amqp.Symbol; +import org.apache.qpid.proton.amqp.UnsignedByte; +import org.apache.qpid.proton.amqp.UnsignedInteger; +import org.apache.qpid.proton.amqp.messaging.*; + +import javax.jms.*; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; + +/** +* @author <a href="http://hiramchirino.com">Hiram Chirino</a> +*/ +public class JMSMappingOutboundTransformer extends OutboundTransformer { + + String prefixDeliveryAnnotations = "DA_"; + String prefixMessageAnnotations= "MA_"; + String prefixFooter = "FT_"; + + public JMSMappingOutboundTransformer(JMSVendor vendor) { + super(vendor); + } + + @Override + public EncodedMessage transform(Message msg) throws Exception { + if( msg == null ) + return null; + try { + if( msg.getBooleanProperty(prefixVendor + "NATIVE") ) { + return null; + } + } catch (MessageFormatException e) { + return null; + } + return transform(this, msg); + } + + static EncodedMessage transform(JMSMappingOutboundTransformer options, Message msg) throws JMSException, UnsupportedEncodingException { + final JMSVendor vendor = options.vendor; + + final String messageFormatKey = options.prefixVendor + "MESSAGE_FORMAT"; + final String nativeKey = options.prefixVendor + "NATIVE"; + final String firstAcquirerKey = options.prefixVendor + "FirstAcquirer"; + final String prefixDeliveryAnnotationsKey = options.prefixVendor + options.prefixDeliveryAnnotations; + final String prefixMessageAnnotationsKey = options.prefixVendor + options.prefixMessageAnnotations; + final String subjectKey = options.prefixVendor +"Subject"; + final String contentTypeKey = options.prefixVendor +"ContentType"; + final String contentEncodingKey = options.prefixVendor +"ContentEncoding"; + final String replyToGroupIDKey = options.prefixVendor +"ReplyToGroupID"; + final String prefixFooterKey = options.prefixVendor + options.prefixFooter; + + long messageFormat; + try { + messageFormat = msg.getLongProperty(messageFormatKey); + } catch (MessageFormatException e) { + return null; + } + + Header header = new Header(); + Properties props=new Properties(); + HashMap<Symbol, Object> daMap = null; + HashMap<Symbol, Object> maMap = null; + HashMap apMap = null; + Section body=null; + HashMap footerMap = null; + if( msg instanceof BytesMessage ) { + BytesMessage m = (BytesMessage)msg; + byte data[] = new byte[(int) m.getBodyLength()]; + m.readBytes(data); + m.reset(); //Need to reset after readBytes or future readBytes calls (ex: redeliveries) will fail and return -1 + body = new Data(new Binary(data)); + } if( msg instanceof TextMessage ) { + body = new AmqpValue(((TextMessage) msg).getText()); + } if( msg instanceof MapMessage ) { + final HashMap map = new HashMap(); + final MapMessage m = (MapMessage) msg; + final Enumeration names = m.getMapNames(); + while (names.hasMoreElements()) { + String key = (String) names.nextElement(); + map.put(key, m.getObject(key)); + } + body = new AmqpValue(map); + } if( msg instanceof StreamMessage ) { + ArrayList list = new ArrayList(); + final StreamMessage m = (StreamMessage) msg; + try { + while(true) { + list.add(m.readObject()); + } + } catch(MessageEOFException e){} + body = new AmqpSequence(list); + } if( msg instanceof ObjectMessage ) { + body = new AmqpValue(((ObjectMessage) msg).getObject()); + } + + header.setDurable(msg.getJMSDeliveryMode() == DeliveryMode.PERSISTENT ? true : false); + header.setPriority(new UnsignedByte((byte) msg.getJMSPriority())); + if( msg.getJMSType()!=null ) { + if( maMap==null ) maMap = new HashMap<Symbol, Object>(); + maMap.put(Symbol.valueOf("x-opt-jms-type"), msg.getJMSType()); + } + if( msg.getJMSMessageID()!=null ) { + props.setMessageId(msg.getJMSMessageID()); + } + if( msg.getJMSDestination()!=null ) { + props.setTo(vendor.toAddress(msg.getJMSDestination())); + if( maMap==null ) maMap = new HashMap(); + maMap.put(Symbol.valueOf("x-opt-to-type"), destinationAttributes(msg.getJMSDestination())); + } + if( msg.getJMSReplyTo()!=null ) { + props.setReplyTo(vendor.toAddress(msg.getJMSReplyTo())); + if( maMap==null ) maMap = new HashMap(); + maMap.put(Symbol.valueOf("x-opt-reply-type"), destinationAttributes(msg.getJMSReplyTo())); + } + if( msg.getJMSCorrelationID()!=null ) { + props.setCorrelationId(msg.getJMSCorrelationID()); + } + if( msg.getJMSExpiration() != 0 ) { + long ttl = msg.getJMSExpiration() - System.currentTimeMillis(); + if (ttl < 0) { + ttl = 1; + } + header.setTtl(new UnsignedInteger((int)ttl)); + + props.setAbsoluteExpiryTime(new Date(msg.getJMSExpiration())); + } + if( msg.getJMSTimestamp()!= 0 ) { + props.setCreationTime(new Date(msg.getJMSTimestamp())); + } + + final Enumeration keys = msg.getPropertyNames(); + while (keys.hasMoreElements()) { + String key = (String) keys.nextElement(); + if( key.equals(messageFormatKey) || key.equals(nativeKey)) { + // skip.. + } else if( key.equals(firstAcquirerKey) ) { + header.setFirstAcquirer(msg.getBooleanProperty(key)); + } else if( key.startsWith("JMSXDeliveryCount") ) { + header.setDeliveryCount(new UnsignedInteger(msg.getIntProperty(key))); + } else if( key.startsWith("JMSXUserID") ) { + String value = msg.getStringProperty(key); + props.setUserId(new Binary(value.getBytes("UTF-8"))); + } else if( key.startsWith("JMSXGroupID") ) { + String value = msg.getStringProperty(key); + props.setGroupId(value); + if( apMap==null ) apMap = new HashMap(); + apMap.put(key, value); + } else if( key.startsWith("JMSXGroupSeq") ) { + UnsignedInteger value = new UnsignedInteger(msg.getIntProperty(key)); + props.setGroupSequence(value); + if( apMap==null ) apMap = new HashMap(); + apMap.put(key, value); + } else if( key.startsWith(prefixDeliveryAnnotationsKey) ) { + if( daMap == null ) daMap = new HashMap<Symbol, Object>(); + String name = key.substring(prefixDeliveryAnnotationsKey.length()); + daMap.put(Symbol.valueOf(name), msg.getObjectProperty(key)); + } else if( key.startsWith(prefixMessageAnnotationsKey) ) { + if( maMap==null ) maMap = new HashMap<Symbol, Object>(); + String name = key.substring(prefixMessageAnnotationsKey.length()); + maMap.put(Symbol.valueOf(name), msg.getObjectProperty(key)); + } else if( key.equals(subjectKey) ) { + props.setSubject(msg.getStringProperty(key)); + } else if( key.equals(contentTypeKey) ) { + props.setContentType(Symbol.getSymbol(msg.getStringProperty(key))); + } else if( key.equals(contentEncodingKey) ) { + props.setContentEncoding(Symbol.getSymbol(msg.getStringProperty(key))); + } else if( key.equals(replyToGroupIDKey) ) { + props.setReplyToGroupId(msg.getStringProperty(key)); + } else if( key.startsWith(prefixFooterKey) ) { + if( footerMap==null ) footerMap = new HashMap(); + String name = key.substring(prefixFooterKey.length()); + footerMap.put(name, msg.getObjectProperty(key)); + } else { + if( apMap==null ) apMap = new HashMap(); + apMap.put(key, msg.getObjectProperty(key)); + } + } + + + MessageAnnotations ma=null; + if( maMap!=null ) ma = new MessageAnnotations(maMap); + DeliveryAnnotations da=null; + if( daMap!=null ) da = new DeliveryAnnotations(daMap); + ApplicationProperties ap=null; + if( apMap!=null ) ap = new ApplicationProperties(apMap); + Footer footer=null; + if( footerMap!=null ) footer = new Footer(footerMap); + + ProtonJMessage amqp = (ProtonJMessage) org.apache.qpid.proton.message.Message.Factory.create(header, da, ma, props, ap, body, footer); + + ByteBuffer buffer = ByteBuffer.wrap(new byte[1024*4]); + final DroppingWritableBuffer overflow = new DroppingWritableBuffer(); + int c = amqp.encode(new CompositeWritableBuffer(new WritableBuffer.ByteBufferWrapper(buffer), overflow)); + if( overflow.position() > 0 ) { + buffer = ByteBuffer.wrap(new byte[1024*4+overflow.position()]); + c = amqp.encode(new WritableBuffer.ByteBufferWrapper(buffer)); + } + + return new EncodedMessage(messageFormat, buffer.array(), 0, c); + } + + private static String destinationAttributes(Destination destination) { + if( destination instanceof Queue ) { + if( destination instanceof TemporaryQueue ) { + return "temporary,queue"; + } else { + return "queue"; + } + } + if( destination instanceof Topic ) { + if( destination instanceof TemporaryTopic ) { + return "temporary,topic"; + } else { + return "topic"; + } + } + return ""; + } +} http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSVendor.java ---------------------------------------------------------------------- diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSVendor.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSVendor.java new file mode 100644 index 0000000..5d02069 --- /dev/null +++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSVendor.java @@ -0,0 +1,45 @@ +package org.apache.qpid.proton.jms; + +import javax.jms.*; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * @author <a href="http://hiramchirino.com">Hiram Chirino</a> + */ +abstract public class JMSVendor { + + public abstract BytesMessage createBytesMessage(); + + public abstract StreamMessage createStreamMessage(); + + public abstract Message createMessage(); + + public abstract TextMessage createTextMessage(); + + public abstract ObjectMessage createObjectMessage(); + + public abstract MapMessage createMapMessage(); + + public abstract void setJMSXUserID(Message msg, String value); + + @Deprecated + public Destination createDestination(String name) { + return null; + } + + @SuppressWarnings("deprecation") + public <T extends Destination> T createDestination(String name, Class<T> kind) { + return kind.cast(createDestination(name)); + } + + public abstract void setJMSXGroupID(Message msg, String groupId); + + public abstract void setJMSXGroupSequence(Message msg, int i); + + public abstract void setJMSXDeliveryCount(Message rc, long l); + + public abstract String toAddress(Destination msgDestination); + +} http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/OutboundTransformer.java ---------------------------------------------------------------------- diff --git a/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/OutboundTransformer.java b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/OutboundTransformer.java new file mode 100644 index 0000000..87175b0 --- /dev/null +++ b/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/OutboundTransformer.java @@ -0,0 +1,52 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.qpid.proton.jms; + +import org.apache.qpid.proton.engine.Delivery; + +import javax.jms.Message; + +/** +* @author <a href="http://hiramchirino.com">Hiram Chirino</a> +*/ +public abstract class OutboundTransformer { + + JMSVendor vendor; + String prefixVendor = "JMS_AMQP_"; + + public OutboundTransformer(JMSVendor vendor) { + this.vendor = vendor; + } + + public abstract EncodedMessage transform(Message jms) throws Exception; + + public String getPrefixVendor() { + return prefixVendor; + } + + public void setPrefixVendor(String prefixVendor) { + this.prefixVendor = prefixVendor; + } + + public JMSVendor getVendor() { + return vendor; + } + + public void setVendor(JMSVendor vendor) { + this.vendor = vendor; + } +} http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/examples/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 4f7f948..7b01b00 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -19,4 +19,5 @@ set (Proton_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) add_subdirectory(messenger/c) http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/examples/messenger/java/recv ---------------------------------------------------------------------- diff --git a/examples/messenger/java/recv b/examples/messenger/java/recv index 7092148..9c6409d 100755 --- a/examples/messenger/java/recv +++ b/examples/messenger/java/recv @@ -6,7 +6,7 @@ HERE=$(cd $(dirname $0); pwd) TOP=$(cd $(dirname $0); cd ../../..; pwd) -LIBS=$HERE/target/classes:$TOP/proton-j/proton-api/target/classes:$TOP/proton-j/proton/target/classes +LIBS=$HERE/target/classes:$TOP/proton-j/target/classes JFLAGS="-Djava.util.logging.config.file=$HERE/recv.trace.props -cp $LIBS" java -cp $LIBS org.apache.qpid.proton.example.Recv "$@" http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/examples/messenger/java/send ---------------------------------------------------------------------- diff --git a/examples/messenger/java/send b/examples/messenger/java/send index 280eeba..d304f20 100755 --- a/examples/messenger/java/send +++ b/examples/messenger/java/send @@ -4,7 +4,7 @@ HERE=$(cd $(dirname $0); pwd) TOP=$(cd $(dirname $0); cd ../../..; pwd) -LIBS=$HERE/target/classes:$TOP/proton-j/proton-api/target/classes:$TOP/proton-j/proton/target/classes +LIBS=$HERE/target/classes:$TOP/proton-j/target/classes JFLAGS="-Djava.util.logging.config.file=$HERE/send.trace.props -cp $LIBS" java -cp $LIBS org.apache.qpid.proton.example.Send "$@" http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/examples/messenger/java/src/main/java/org/apache/qpid/proton/example/Send.java ---------------------------------------------------------------------- diff --git a/examples/messenger/java/src/main/java/org/apache/qpid/proton/example/Send.java b/examples/messenger/java/src/main/java/org/apache/qpid/proton/example/Send.java index e0e1f42..56bce55 100644 --- a/examples/messenger/java/src/main/java/org/apache/qpid/proton/example/Send.java +++ b/examples/messenger/java/src/main/java/org/apache/qpid/proton/example/Send.java @@ -40,9 +40,9 @@ import java.util.logging.Logger; public class Send { private static Logger tracer = Logger.getLogger("proton.example"); - private String address = "amqp://0.0.0.0/test"; + private String address = "amqp://0.0.0.0"; private String subject; - private String[] bodies; + private String[] bodies = new String[]{"Hello World!"}; private static void usage() { System.err.println("Usage: send [-a ADDRESS] [-s SUBJECT] MSG+"); @@ -67,7 +67,11 @@ public class Send { break; } } - bodies = Arrays.copyOfRange(args, i, args.length); + + if(i != args.length) + { + bodies = Arrays.copyOfRange(args, i, args.length); + } } private void run() { http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/examples/messenger/javascript/send.html ---------------------------------------------------------------------- diff --git a/examples/messenger/javascript/send.html b/examples/messenger/javascript/send.html index b6aaef2..eff1fad 100644 --- a/examples/messenger/javascript/send.html +++ b/examples/messenger/javascript/send.html @@ -58,7 +58,17 @@ console.log("body = " + body); messenger.put(message); }; -messenger.on('error', function(error) {console.log("Received error " + error);}); +messenger.on('error', function(error) { + console.log("Received error " + error); + +message.free(); +messenger.free(); +message = new proton.Message(); +messenger = new proton.Messenger(); +messenger.start(); +console.log("Restarted"); +}); + messenger.start(); </script> http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/examples/messenger/perl/recv.pl ---------------------------------------------------------------------- diff --git a/examples/messenger/perl/recv.pl b/examples/messenger/perl/recv.pl index 6e4f273..801f6a2 100755 --- a/examples/messenger/perl/recv.pl +++ b/examples/messenger/perl/recv.pl @@ -18,9 +18,11 @@ # under the License. # -use strict; use warnings; +use Scalar::Util qw(reftype); +use Data::Dumper; + use qpid_proton; sub usage { @@ -48,10 +50,34 @@ for(;;) while ($messenger->incoming() > 0) { $messenger->get($msg); + + print "\n"; print "Address: " . $msg->get_address() . "\n"; - print "Subject: " . $msg->get_subject() . "\n"; - print "Content: " . $msg->get_content() . "\n"; - print "Body: " . $msg->get_body() . "\n"; + print "Subject: " . $msg->get_subject() . "\n" unless !defined($msg->get_subject()); + print "Body: "; + + my $body = $msg->get_body(); + my $body_type = $msg->get_body_type(); + + if (!defined($body_type)) { + print "The body type wasn't defined!\n"; + } elsif ($body_type == qpid::proton::BOOL) { + print "[BOOL]\n"; + print "" . ($body ? "TRUE" : "FALSE") . "\n"; + } elsif ($body_type == qpid::proton::MAP) { + print "[HASH]\n"; + print Dumper(\%{$body}) . "\n"; + } elsif ($body_type == qpid::proton::ARRAY) { + print "[ARRAY]\n"; + print Data::Dumper->Dump($body) . "\n"; + } elsif ($body_type == qpid::proton::LIST) { + print "[LIST]\n"; + print Data::Dumper->Dump($body) . "\n"; + } else { + print "[$body_type]\n"; + print "$body\n"; + } + print "Properties:\n"; my $props = $msg->get_properties(); foreach (keys $props) { http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/examples/messenger/perl/send.pl ---------------------------------------------------------------------- diff --git a/examples/messenger/perl/send.pl b/examples/messenger/perl/send.pl index 9d907d6..b622b68 100755 --- a/examples/messenger/perl/send.pl +++ b/examples/messenger/perl/send.pl @@ -34,11 +34,14 @@ sub HELP_MESSAGE() { print "Options:\n"; print "\t-s - the message subject\n"; print "\t-C - the message content\n"; - print "\t<ADDRESS> - amqp://<domain>[/<name>]"; + print "\t<ADDRESS> - amqp://<domain>[/<name>]\n"; + print "\t-h - this message\n"; + + exit; } my %options = (); -getopts("a:C:s:", \%options) or usage(); +getopts("a:C:s:h:", \%options) or HELP_MESSAGE(); my $address = $options{a} || "amqp://0.0.0.0"; my $subject = $options{s} || localtime(time); @@ -58,7 +61,7 @@ foreach (@messages) $msg->set_subject($subject); $msg->set_content($content); # try a few different body types - my $body_type = int(rand(4)); + my $body_type = int(rand(6)); $msg->set_property("sent", "" . localtime(time)); $msg->get_instructions->{"fold"} = "yes"; $msg->get_instructions->{"spindle"} = "no"; @@ -68,12 +71,15 @@ foreach (@messages) SWITCH: { $body_type == 0 && do { $msg->set_body("It is now " . localtime(time));}; - $body_type == 1 && do { $msg->set_body(rand(65536), qpid::proton::FLOAT); }; + $body_type == 1 && do { $msg->set_body(rand(65536)); }; $body_type == 2 && do { $msg->set_body(int(rand(2)), qpid::proton::BOOL); }; - $body_type == 3 && do { $msg->set_body({"foo" => "bar"}, qpid::proton::MAP); }; + $body_type == 3 && do { $msg->set_body({"foo" => "bar"}); }; + $body_type == 4 && do { $msg->set_body([4, [1, 2, 3.1, 3.4E-5], 8, 15, 16, 23, 42]); }; + $body_type == 5 && do { $msg->set_body(int(rand(65535))); } } $messenger->put($msg); + print "Sent: " . $msg->get_body . " [CONTENT TYPE: " . $msg->get_body_type . "]\n"; } $messenger->send(); http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/examples/messenger/perl/server.pl ---------------------------------------------------------------------- diff --git a/examples/messenger/perl/server.pl b/examples/messenger/perl/server.pl index 25d1a44..c13d4d5 100755 --- a/examples/messenger/perl/server.pl +++ b/examples/messenger/perl/server.pl @@ -58,8 +58,10 @@ sub dispatch { $reply->set_properties($request->get_properties); print "Dispatched " . $request->get_subject . "\n"; - foreach (keys $request->get_properties) { - print "\t$_:" . $request->get_properties->{$_} . "\n"; + my $properties = $request->get_properties; + foreach (keys %{$properties}) { + my $value = $properties->{%_}; + print "\t$_: $value\n"; } } http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt index 76b082b..9f74b10 100644 --- a/proton-c/CMakeLists.txt +++ b/proton-c/CMakeLists.txt @@ -58,26 +58,30 @@ configure_file ( "${CMAKE_CURRENT_BINARY_DIR}/include/proton/version.h" ) -include_directories ("${CMAKE_CURRENT_BINARY_DIR}") +include_directories ("${CMAKE_CURRENT_BINARY_DIR}/src") include_directories ("${CMAKE_CURRENT_BINARY_DIR}/include") +include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/src") include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/include") -include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/../examples/include") + +# TODO: This is only needed because the proton executable can use getopt on windows +# if/when this executable gets sorted out remove +include_directories ("${CMAKE_SOURCE_DIR}/examples/include") add_custom_command ( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/encodings.h - COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/env.py PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/src/codec/encodings.h.py > ${CMAKE_CURRENT_BINARY_DIR}/encodings.h + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/env.py PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/src/codec/encodings.h.py > ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/codec/encodings.h.py ) add_custom_command ( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/protocol.h - COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/env.py PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/src/protocol.h.py > ${CMAKE_CURRENT_BINARY_DIR}/protocol.h + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/protocol.h + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/env.py PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/src/protocol.h.py > ${CMAKE_CURRENT_BINARY_DIR}/src/protocol.h DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/protocol.h.py ) # Select driver if(PN_WINAPI) - set (pn_io_impl src/windows/io.c) + set (pn_io_impl src/windows/io.c src/windows/iocp.c src/windows/write_pipeline.c) set (pn_selector_impl src/windows/selector.c) set (pn_driver_impl src/windows/driver.c) else(PN_WINAPI) @@ -89,6 +93,7 @@ endif(PN_WINAPI) # Link in openssl if present if (SSL_IMPL STREQUAL openssl) set (pn_driver_ssl_impl src/ssl/openssl.c) + include_directories ("${OPENSSL_INCLUDE_DIR}") set (SSL_LIB ${OPENSSL_LIBRARIES}) else (SSL_IMPL STREQUAL openssl) set (pn_driver_ssl_impl src/ssl/ssl_stub.c) @@ -220,7 +225,13 @@ if (CMAKE_COMPILER_IS_GNUCC) endif (CMAKE_COMPILER_IS_GNUCC) if (MSVC) - set(CMAKE_DEBUG_POSTFIX "d") + set(CMAKE_DEBUG_POSTFIX "d") + add_definitions( + /wd4244 + /wd4267 + /wd4800 + /wd4996 + ) endif (MSVC) macro (pn_absolute_install_dir NAME VALUE PREFIX) @@ -293,8 +304,8 @@ set (qpid-proton-core src/messenger/transform.c src/selectable.c - ${CMAKE_CURRENT_BINARY_DIR}/encodings.h - ${CMAKE_CURRENT_BINARY_DIR}/protocol.h + ${CMAKE_CURRENT_BINARY_DIR}/src/encodings.h + ${CMAKE_CURRENT_BINARY_DIR}/src/protocol.h ) set_source_files_properties ( @@ -368,6 +379,18 @@ install (TARGETS qpid-proton ARCHIVE DESTINATION ${LIB_INSTALL_DIR} LIBRARY DESTINATION ${LIB_INSTALL_DIR}) +# Install windows qpid-proton pdb files +if (MSVC) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Debug/qpid-proton${CMAKE_DEBUG_POSTFIX}.pdb + DESTINATION bin + CONFIGURATIONS Debug + OPTIONAL) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/qpid-proton.pdb + DESTINATION bin + CONFIGURATIONS RelWithDebInfo + OPTIONAL) +endif (MSVC) + # Install header files file(GLOB headers "include/proton/*.[hi]") install (FILES ${headers} DESTINATION ${INCLUDE_INSTALL_DIR}/proton) @@ -464,10 +487,10 @@ set (py_bin "${CMAKE_CURRENT_BINARY_DIR}/bindings/python") set (py_bld "${CMAKE_CURRENT_BINARY_DIR}${bld_suffix}") # For windows set (app_path "${pn_test_bin}/tools/apps/c${bld_suffix}") set (app_path "${app_path}:${pn_test_root}/tools/apps/python") -set_path (py_path "$ENV{PATH}:${py_bin}:${py_bld}:${app_path}") -set_path (py_pythonpath "$ENV{PYTHONPATH}:${py_root}:${py_src}:${py_bin}:${py_bld}") +set_path (py_path "${py_bin}:${py_bld}:${app_path}:$ENV{PATH}") +set_path (py_pythonpath "${py_root}:${py_src}:${py_bin}:${py_bld}|$ENV{PYTHONPATH}") if (CMAKE_SYSTEM_NAME STREQUAL Windows) - set_path (py_pythonpath "${py_pythonpath}:${py_bin}${bld_suffix}") + set_path (py_pythonpath "${py_bin}${bld_suffix}:${py_pythonpath}") endif (CMAKE_SYSTEM_NAME STREQUAL Windows) add_test (python-test ${PYTHON_EXECUTABLE} ${env_py} "PATH=${py_path}" "PYTHONPATH=${py_pythonpath}" ${VALGRIND_ENV} http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/proton-c/bindings/CMakeLists.txt b/proton-c/bindings/CMakeLists.txt index 70cc552..b5e6fba 100644 --- a/proton-c/bindings/CMakeLists.txt +++ b/proton-c/bindings/CMakeLists.txt @@ -62,7 +62,9 @@ if (RUBY_FOUND) if (HAS_RUBY_GEM_RSPEC AND HAS_RUBY_GEM_SIMPLECOV) set (DEFAULT_RUBY_TESTING ON CACHE INTERNAL "") else() + message(STATUS "Skipping Ruby bindings due to missing dependencies...") set (DEFAULT_RUBY_TESTING OFF CACHE INTERNAL "") + set (DEFAULT_RUBY OFF) endif (HAS_RUBY_GEM_RSPEC AND HAS_RUBY_GEM_SIMPLECOV) endif (RUBY_FOUND) http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/javascript/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/proton-c/bindings/javascript/CMakeLists.txt b/proton-c/bindings/javascript/CMakeLists.txt index ae24407..02f9ccb 100644 --- a/proton-c/bindings/javascript/CMakeLists.txt +++ b/proton-c/bindings/javascript/CMakeLists.txt @@ -43,10 +43,14 @@ set(CMAKE_C_COMPILER "${EMCC}") include(CMakeForceCompiler) CMAKE_FORCE_C_COMPILER("${CMAKE_C_COMPILER}" Clang) -if (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") - message(STATUS "DEBUG JavaScript build") +# The Proton default build type is RelWithDebInfo, but for JavaScript the C debug +# mechanism is irrelevant. If Debug is explicitly set we turn off optimisations +# and don't run the closure compiler so any error/profiling messages are readable. +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + message(STATUS "JavaScript build type is \"Debug\"") else() - message(STATUS "RELEASE JavaScript build") + set (CMAKE_BUILD_TYPE Release) + message(STATUS "JavaScript build type is \"Release\"") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") set(EMSCRIPTEN_LINK_OPTIMISATIONS "-O2 --closure 1") endif() http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/perl/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/proton-c/bindings/perl/CMakeLists.txt b/proton-c/bindings/perl/CMakeLists.txt index 365439b..2a25327 100644 --- a/proton-c/bindings/perl/CMakeLists.txt +++ b/proton-c/bindings/perl/CMakeLists.txt @@ -43,7 +43,9 @@ if (NOT PERL_VENDORARCH_DIR) endif() set (CMAKE_C_FLAGS ${PERLCFLAGS}) - +list(APPEND SWIG_MODULE_cproton_perl_EXTRA_DEPS + ${CMAKE_SOURCE_DIR}/proton-c/include/proton/cproton.i +) swig_add_module(cproton_perl perl perl.i) swig_link_libraries(cproton_perl ${BINDING_DEPS} ${PERL_LIBRARY}) http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/perl/lib/qpid/proton/Constants.pm ---------------------------------------------------------------------- diff --git a/proton-c/bindings/perl/lib/qpid/proton/Constants.pm b/proton-c/bindings/perl/lib/qpid/proton/Constants.pm index 8397011..2cb93e7 100644 --- a/proton-c/bindings/perl/lib/qpid/proton/Constants.pm +++ b/proton-c/bindings/perl/lib/qpid/proton/Constants.pm @@ -20,6 +20,9 @@ package qpid::proton; use constant { + VERSION_MAJOR => $cproton_perl::PN_VERSION_MAJOR, + VERSION_MINOR => $cproton_perl::PN_VERSION_MINOR, + NULL => $cproton_perl::PN_NULL, BOOL => qpid::proton::Mapping->new( "bool", @@ -129,8 +132,8 @@ use constant { LIST => qpid::proton::Mapping->new( "list", $cproton_perl::PN_LIST, - "put_list", - "get_list"), + "put_list_helper", + "get_list_helper"), MAP => qpid::proton::Mapping->new( "map", $cproton_perl::PN_MAP, http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/perl/lib/qpid/proton/Data.pm ---------------------------------------------------------------------- diff --git a/proton-c/bindings/perl/lib/qpid/proton/Data.pm b/proton-c/bindings/perl/lib/qpid/proton/Data.pm index 90f5ecb..156e09a 100644 --- a/proton-c/bindings/perl/lib/qpid/proton/Data.pm +++ b/proton-c/bindings/perl/lib/qpid/proton/Data.pm @@ -17,7 +17,7 @@ # under the License. # -use Scalar::Util qw(looks_like_number); +use Scalar::Util qw(reftype looks_like_number); =pod @@ -321,9 +321,7 @@ Handles a boolean (B<true>/B<false>) node. sub put_bool { my ($self) = @_; my $impl = $self->{_impl}; - my $value = $_[1]; - - die "bool must be defined" if !defined($value); + my $value = $_[1] || 0; cproton_perl::pn_data_put_bool($impl, $value); } @@ -1159,16 +1157,90 @@ sub get_map { cproton_perl::pn_data_get_map($impl); } +sub put_list_helper { + my ($self) = @_; + my ($array) = $_[1]; + + $self->put_list; + $self->enter; + + for my $value (@{$array}) { + if (qpid::proton::is_num($value)) { + if (qpid::proton::is_float($value)) { + $self->put_float($value); + } else { + $self->put_int($value); + } + } elsif (!defined($value)) { + $self->put_null; + } elsif ($value eq '') { + $self->put_string($value); + } elsif (ref($value) eq 'HASH') { + $self->put_map_helper($value); + } elsif (ref($value) eq 'ARRAY') { + $self->put_list_helper($value); + } else { + $self->put_string($value); + } + } + + $self->exit; +} + +sub get_list_helper { + my ($self) = @_; + my $result = []; + my $type = $self->get_type; + + if ($cproton_perl::PN_LIST == $type->get_type_value) { + my $size = $self->get_list; + + $self->enter; + + for(my $count = 0; $count < $size; $count++) { + if ($self->next) { + my $value_type = $self->get_type; + my $value = $value_type->get($self); + + push(@{$result}, $value); + } + } + + $self->exit; + } + + return $result; +} + sub put_map_helper { my ($self) = @_; - my ($hash) = $_[1]; + my $hash = $_[1]; $self->put_map; $self->enter; - foreach(keys $hash) { - $self->put_string("$_"); - $self->put_string("$hash->{$_}"); + foreach(keys %{$hash}) { + my $key = $_; + my $value = $hash->{$key}; + + my $keytype = ::reftype($key); + my $valtype = ::reftype($value); + + if ($keytype eq ARRAY) { + $self->put_list_helper($key); + } elsif ($keytype eq "HASH") { + $self->put_map_helper($key); + } else { + $self->put_string("$key"); + } + + if (::reftype($value) eq HASH) { + $self->put_map_helper($value); + } elsif (::reftype($value) eq ARRAY) { + $self->put_list_helper($value); + } else { + $self->put_string("$value"); + } } $self->exit; @@ -1193,9 +1265,10 @@ sub get_map_helper { } } } - } - $self->exit; + $self->exit; + + } return $result; } http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/perl/lib/qpid/proton/Message.pm ---------------------------------------------------------------------- diff --git a/proton-c/bindings/perl/lib/qpid/proton/Message.pm b/proton-c/bindings/perl/lib/qpid/proton/Message.pm index 8a38988..49aeccd 100644 --- a/proton-c/bindings/perl/lib/qpid/proton/Message.pm +++ b/proton-c/bindings/perl/lib/qpid/proton/Message.pm @@ -443,7 +443,29 @@ B<qpid::proton::STRING>. sub set_body { my ($self) = @_; my $body = $_[1]; - my $body_type = $_[2] || qpid::proton::STRING; + my $body_type = $_[2] || undef; + + # if no body type was defined, then attempt to infer what it should + # be, which is going to be a best guess + if (!defined($body_type)) { + if (qpid::proton::is_num($body)) { + if (qpid::proton::is_float($body)) { + $body_type = qpid::proton::FLOAT; + } else { + $body_type = qpid::proton::INT; + } + } elsif (!defined($body)) { + $body_type = qpid::proton::NULL; + } elsif ($body eq '') { + $body_type = qpid::proton::STRING; + } elsif (ref($body) eq 'HASH') { + $body_type = qpid::proton::MAP; + } elsif (ref($body) eq 'ARRAY') { + $body_type = qpid::proton::LIST; + } else { + $body_type = qpid::proton::STRING; + } + } $self->{_body} = $body; $self->{_body_type} = $body_type; @@ -465,12 +487,12 @@ sub get_body_type { sub preencode() { my ($self) = @_; my $impl = $self->{_impl}; - my $my_body = $self->{_body}; my $body_type = $self->{_body_type}; my $body = new qpid::proton::Data(cproton_perl::pn_message_body($impl)); + $body->clear(); - $body_type->put($body, $my_body) if($my_body && $body_type); + $body_type->put($body, $my_body) if(defined($my_body) && $body_type); my $my_props = $self->{_properties}; my $props = new qpid::proton::Data(cproton_perl::pn_message_properties($impl)); http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/perl/lib/qpid/proton/utils.pm ---------------------------------------------------------------------- diff --git a/proton-c/bindings/perl/lib/qpid/proton/utils.pm b/proton-c/bindings/perl/lib/qpid/proton/utils.pm new file mode 100644 index 0000000..75af498 --- /dev/null +++ b/proton-c/bindings/perl/lib/qpid/proton/utils.pm @@ -0,0 +1,31 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +package qpid::proton; + +sub is_num { + my $val = $_[0]; + + return 0 if !defined($val); + return 0 if $val eq ''; + + $_[0] ^ $_[0] ? 0 : 1 +} + +1; http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/perl/lib/qpid_proton.pm ---------------------------------------------------------------------- diff --git a/proton-c/bindings/perl/lib/qpid_proton.pm b/proton-c/bindings/perl/lib/qpid_proton.pm index dc7fefb..de4e224 100644 --- a/proton-c/bindings/perl/lib/qpid_proton.pm +++ b/proton-c/bindings/perl/lib/qpid_proton.pm @@ -21,6 +21,7 @@ use strict; use warnings; use cproton_perl; +use qpid::proton::utils; use qpid::proton::ExceptionHandling; use qpid::proton::Data; use qpid::proton::Mapping; http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/perl/perl.i ---------------------------------------------------------------------- diff --git a/proton-c/bindings/perl/perl.i b/proton-c/bindings/perl/perl.i index cc6a4d7..ad059f3 100644 --- a/proton-c/bindings/perl/perl.i +++ b/proton-c/bindings/perl/perl.i @@ -10,13 +10,6 @@ #include <proton/driver_extras.h> %} -typedef unsigned int size_t; -typedef signed int ssize_t; -typedef unsigned char uint8_t; -typedef unsigned int uint32_t; -typedef unsigned long int uint64_t; -typedef int int32_t; - %include <cstring.i> %typemap(in) pn_atom_t http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/php/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/proton-c/bindings/php/CMakeLists.txt b/proton-c/bindings/php/CMakeLists.txt index 762e05b..637f692 100644 --- a/proton-c/bindings/php/CMakeLists.txt +++ b/proton-c/bindings/php/CMakeLists.txt @@ -30,6 +30,9 @@ execute_process(COMMAND ${PHP_CONFIG_EXE} --includes OUTPUT_STRIP_TRAILING_WHITESPACE) set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/php.i PROPERTIES SWIG_FLAGS "-I${PROJECT_SOURCE_DIR}/include") +list(APPEND SWIG_MODULE_cproton_EXTRA_DEPS + ${CMAKE_SOURCE_DIR}/proton-c/include/proton/cproton.i +) swig_add_module(cproton php ${CMAKE_CURRENT_SOURCE_DIR}/php.i) set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_FLAGS "${PHP_INCLUDES}") swig_link_libraries(cproton ${BINDING_DEPS}) http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/php/proton.php ---------------------------------------------------------------------- diff --git a/proton-c/bindings/php/proton.php b/proton-c/bindings/php/proton.php index 4c3e4ef..2e2a69a 100644 --- a/proton-c/bindings/php/proton.php +++ b/proton-c/bindings/php/proton.php @@ -286,7 +286,7 @@ class Message { if ($ann->next()) $this->annotations = $ann->get_object(); else - $self->annotations = null; + $this->annotations = null; if ($props->next()) $this->properties = $props->get_object(); else http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/python/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/proton-c/bindings/python/CMakeLists.txt b/proton-c/bindings/python/CMakeLists.txt index 7853e18..b8cdb57 100644 --- a/proton-c/bindings/python/CMakeLists.txt +++ b/proton-c/bindings/python/CMakeLists.txt @@ -16,41 +16,38 @@ # specific language governing permissions and limitations # under the License. # + +# NB For python the SWIG module name must have the same name as the +# input .i file for CMake to generate the correct dependencies + set(CMAKE_SWIG_FLAGS "-threads") include_directories (${PYTHON_INCLUDE_PATH}) if (BUILD_WITH_CXX) - SET_SOURCE_FILES_PROPERTIES(python.i PROPERTIES CPLUSPLUS ON) + SET_SOURCE_FILES_PROPERTIES(cproton.i PROPERTIES CPLUSPLUS ON) endif (BUILD_WITH_CXX) -swig_add_module(cproton python python.i) + +list(APPEND SWIG_MODULE_cproton_EXTRA_DEPS + ${CMAKE_SOURCE_DIR}/proton-c/include/proton/cproton.i +) + +swig_add_module(cproton python cproton.i) swig_link_libraries(cproton ${BINDING_DEPS} ${PYTHON_LIBRARIES}) -set_target_properties(_cproton +set_target_properties(${SWIG_MODULE_cproton_REAL_NAME} PROPERTIES LINK_FLAGS "${CATCH_UNDEFINED}") find_package(PythonInterp REQUIRED) -if (CHECK_SYSINSTALL_PYTHON) - execute_process(COMMAND ${PYTHON_EXECUTABLE} - -c "from distutils.sysconfig import get_python_lib; print get_python_lib(True)" - OUTPUT_VARIABLE PYTHON_SITEARCH_PACKAGES_DEFAULT - OUTPUT_STRIP_TRAILING_WHITESPACE) -else () - set (PYTHON_SITEARCH_PACKAGES_DEFAULT ${BINDINGS_DIR}/python) -endif () - -if (NOT PYTHON_SITEARCH_PACKAGES) - set (PYTHON_SITEARCH_PACKAGES ${PYTHON_SITEARCH_PACKAGES_DEFAULT}) -endif() - -install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile cproton.py - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") -install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile cproton.py - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") -install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile proton.py - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})") -install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile proton.py - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})") +# configure the files needed for generating Pypi packages. Packages +# can be generated by running "python setup.py" from the build +# directory. +get_filename_component(PN_SWIG_PYTHON_C_WRAPPER + ${swig_generated_file_fullname} NAME) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/proton.py + ${CMAKE_CURRENT_BINARY_DIR} COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in + ${CMAKE_CURRENT_BINARY_DIR}/setup.py @ONLY) find_program(EPYDOC_EXE epydoc) mark_as_advanced (EPYDOC_EXE) @@ -66,14 +63,37 @@ if (EPYDOC_EXE) ${OPTIONAL_ARG}) endif (EPYDOC_EXE) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cproton.py - ${CMAKE_CURRENT_BINARY_DIR}/cproton.pyc - ${CMAKE_CURRENT_BINARY_DIR}/cproton.pyo - ${CMAKE_CURRENT_SOURCE_DIR}/proton.py - ${CMAKE_CURRENT_SOURCE_DIR}/proton.pyc - ${CMAKE_CURRENT_SOURCE_DIR}/proton.pyo - DESTINATION ${PYTHON_SITEARCH_PACKAGES} - COMPONENT Python) -install(TARGETS _cproton - DESTINATION ${PYTHON_SITEARCH_PACKAGES} - COMPONENT Python) +if (CHECK_SYSINSTALL_PYTHON) + # use the python-native install paths: + + install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} setup.py sdist + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") + install(CODE "execute_process(COMMAND + ${PYTHON_EXECUTABLE} setup.py --proton-install-prefix ${CMAKE_INSTALL_PREFIX} install + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") + +else () + # install the bindings using the CMAKE path variables: + set (PYTHON_SITEARCH_PACKAGES ${BINDINGS_DIR}/python) + + install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile cproton.py + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") + install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile cproton.py + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") + install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile proton.py + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})") + install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile proton.py + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})") + + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cproton.py + ${CMAKE_CURRENT_BINARY_DIR}/cproton.pyc + ${CMAKE_CURRENT_BINARY_DIR}/cproton.pyo + ${CMAKE_CURRENT_SOURCE_DIR}/proton.py + ${CMAKE_CURRENT_SOURCE_DIR}/proton.pyc + ${CMAKE_CURRENT_SOURCE_DIR}/proton.pyo + DESTINATION ${PYTHON_SITEARCH_PACKAGES} + COMPONENT Python) + install(TARGETS ${SWIG_MODULE_cproton_REAL_NAME} + DESTINATION ${PYTHON_SITEARCH_PACKAGES} + COMPONENT Python) +endif() http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/python/cproton.i ---------------------------------------------------------------------- diff --git a/proton-c/bindings/python/cproton.i b/proton-c/bindings/python/cproton.i new file mode 100644 index 0000000..496897f --- /dev/null +++ b/proton-c/bindings/python/cproton.i @@ -0,0 +1,379 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +%module cproton +%{ +/* Includes the header in the wrapper code */ +#if defined(_WIN32) && ! defined(__CYGWIN__) +#include <winsock2.h> +#endif +#include <proton/engine.h> +#include <proton/message.h> +#include <proton/sasl.h> +#include <proton/driver.h> +#include <proton/driver_extras.h> +#include <proton/messenger.h> +#include <proton/ssl.h> +%} + +%include <cstring.i> + +%cstring_output_withsize(char *OUTPUT, size_t *OUTPUT_SIZE) +%cstring_output_allocate_size(char **ALLOC_OUTPUT, size_t *ALLOC_SIZE, free(*$1)); +%cstring_output_maxsize(char *OUTPUT, size_t MAX_OUTPUT_SIZE) + +// These are not used/needed in the python binding +%ignore pn_message_get_id; +%ignore pn_message_set_id; +%ignore pn_message_get_correlation_id; +%ignore pn_message_set_correlation_id; + +%typemap(in) pn_bytes_t { + if ($input == Py_None) { + $1.start = NULL; + $1.size = 0; + } else { + $1.start = PyString_AsString($input); + if (!$1.start) { + return NULL; + } + $1.size = PyString_Size($input); + } +} + +%typemap(out) pn_bytes_t { + $result = PyString_FromStringAndSize($1.start, $1.size); +} + +%typemap(out) pn_delivery_tag_t { + $result = PyString_FromStringAndSize($1.bytes, $1.size); +} + +%typemap(in) pn_uuid_t { + memset($1.bytes, 0, 16); + if ($input == Py_None) { + ; // Already zeroed out + } else { + const char* b = PyString_AsString($input); + if (b) { + memmove($1.bytes, b, (PyString_Size($input) < 16 ? PyString_Size($input) : 16)); + } else { + return NULL; + } + } +} + +%typemap(out) pn_uuid_t { + $result = PyString_FromStringAndSize($1.bytes, 16); +} + +%apply pn_uuid_t { pn_decimal128_t }; + +int pn_message_load(pn_message_t *msg, char *STRING, size_t LENGTH); +%ignore pn_message_load; + +int pn_message_load_data(pn_message_t *msg, char *STRING, size_t LENGTH); +%ignore pn_message_load_data; + +int pn_message_load_text(pn_message_t *msg, char *STRING, size_t LENGTH); +%ignore pn_message_load_text; + +int pn_message_load_amqp(pn_message_t *msg, char *STRING, size_t LENGTH); +%ignore pn_message_load_amqp; + +int pn_message_load_json(pn_message_t *msg, char *STRING, size_t LENGTH); +%ignore pn_message_load_json; + +int pn_message_encode(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE); +%ignore pn_message_encode; + +int pn_message_save(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE); +%ignore pn_message_save; + +int pn_message_save_data(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE); +%ignore pn_message_save_data; + +int pn_message_save_text(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE); +%ignore pn_message_save_text; + +int pn_message_save_amqp(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE); +%ignore pn_message_save_amqp; + +int pn_message_save_json(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE); +%ignore pn_message_save_json; + +ssize_t pn_link_send(pn_link_t *transport, char *STRING, size_t LENGTH); +%ignore pn_link_send; + +%rename(pn_link_recv) wrap_pn_link_recv; +%inline %{ + int wrap_pn_link_recv(pn_link_t *link, char *OUTPUT, size_t *OUTPUT_SIZE) { + ssize_t sz = pn_link_recv(link, OUTPUT, *OUTPUT_SIZE); + if (sz >= 0) { + *OUTPUT_SIZE = sz; + } else { + *OUTPUT_SIZE = 0; + } + return sz; + } +%} +%ignore pn_link_recv; + +ssize_t pn_transport_push(pn_transport_t *transport, char *STRING, size_t LENGTH); +%ignore pn_transport_push; + +%rename(pn_transport_peek) wrap_pn_transport_peek; +%inline %{ + int wrap_pn_transport_peek(pn_transport_t *transport, char *OUTPUT, size_t *OUTPUT_SIZE) { + ssize_t sz = pn_transport_peek(transport, OUTPUT, *OUTPUT_SIZE); + if (sz >= 0) { + *OUTPUT_SIZE = sz; + } else { + *OUTPUT_SIZE = 0; + } + return sz; + } +%} +%ignore pn_transport_peek; + +%rename(pn_delivery) wrap_pn_delivery; +%inline %{ + pn_delivery_t *wrap_pn_delivery(pn_link_t *link, char *STRING, size_t LENGTH) { + return pn_delivery(link, pn_dtag(STRING, LENGTH)); + } +%} +%ignore pn_delivery; + +%rename(pn_delivery_tag) wrap_pn_delivery_tag; +%inline %{ + void wrap_pn_delivery_tag(pn_delivery_t *delivery, char **ALLOC_OUTPUT, size_t *ALLOC_SIZE) { + pn_delivery_tag_t tag = pn_delivery_tag(delivery); + *ALLOC_OUTPUT = (char *) malloc(tag.size); + *ALLOC_SIZE = tag.size; + memcpy(*ALLOC_OUTPUT, tag.bytes, tag.size); + } +%} +%ignore pn_delivery_tag; + +%rename(pn_message_data) wrap_pn_message_data; +%inline %{ + int wrap_pn_message_data(char *STRING, size_t LENGTH, char *OUTPUT, size_t *OUTPUT_SIZE) { + ssize_t sz = pn_message_data(OUTPUT, *OUTPUT_SIZE, STRING, LENGTH); + if (sz >= 0) { + *OUTPUT_SIZE = sz; + } else { + *OUTPUT_SIZE = 0; + } + return sz; + } +%} +%ignore pn_message_data; + +%rename(pn_listener_set_context) wrap_pn_listener_set_context; +%inline { + void wrap_pn_listener_set_context(pn_listener_t *l, PyObject *context) { + // don't incref context: we 'borrow' the reference - prevents + // reference loops. Should be safe as the Python object must + // outlive the C object. + pn_listener_set_context(l, context); + } +} +%ignore pn_listener_set_context; + +%rename(pn_listener_context) wrap_pn_listener_context; +%inline { + PyObject *wrap_pn_listener_context(pn_listener_t *l) { + PyObject *result = (PyObject *) pn_listener_context(l); + // incref the returned context, as the caller expects this + if (result) { + Py_INCREF(result); + return result; + } else { + Py_RETURN_NONE; + } + } +} +%ignore pn_listener_context; + +%rename(pn_connector_set_context) wrap_pn_connector_set_context; +%inline { + void wrap_pn_connector_set_context(pn_connector_t *c, PyObject *context) { + // don't incref context: we 'borrow' the reference - prevents + // reference loops. Should be safe as the Python object must + // outlive the C object. + pn_connector_set_context(c, context); + } +} +%ignore pn_connector_set_context; + +%rename(pn_connector_context) wrap_pn_connector_context; +%inline { + PyObject *wrap_pn_connector_context(pn_connector_t *c) { + PyObject *result = (PyObject *) pn_connector_context(c); + // incref the returned context, as the caller expects this + if (result) { + Py_INCREF(result); + return result; + } else { + Py_RETURN_NONE; + } + } +} +%ignore pn_connector_context; + +%rename(pn_connection_get_context) wrap_pn_connection_get_context; +%inline { + PyObject *wrap_pn_connection_get_context(pn_connection_t *c) { + PyObject *result = (PyObject *) pn_connection_get_context(c); + // incref the returned context, as the caller expects this + if (result) { + Py_INCREF(result); + return result; + } else { + Py_RETURN_NONE; + } + } +} +%ignore pn_connection_get_context; + +%rename(pn_connection_set_context) wrap_pn_connection_set_context; +%inline { + void wrap_pn_connection_set_context(pn_connection_t *c, PyObject *context) { + // don't incref context: we 'borrow' the reference + pn_connection_set_context(c, context); + } +} +%ignore pn_connection_set_context; + +%rename(pn_session_get_context) wrap_pn_session_get_context; +%inline { + PyObject *wrap_pn_session_get_context(pn_session_t *s) { + PyObject *result = (PyObject *) pn_session_get_context(s); + // incref the returned context, as the caller expects this + if (result) { + Py_INCREF(result); + return result; + } else { + Py_RETURN_NONE; + } + } +} +%ignore pn_session_get_context; + +%rename(pn_session_set_context) wrap_pn_session_set_context; +%inline { + void wrap_pn_session_set_context(pn_session_t *s, PyObject *context) { + // don't incref context: we 'borrow' the reference + pn_session_set_context(s, context); + } +} +%ignore pn_session_set_context; + +%rename(pn_link_get_context) wrap_pn_link_get_context; +%inline { + PyObject *wrap_pn_link_get_context(pn_link_t *l) { + PyObject *result = (PyObject *) pn_link_get_context(l); + // incref the returned context, as the caller expects this + if (result) { + Py_INCREF(result); + return result; + } else { + Py_RETURN_NONE; + } + } +} +%ignore pn_link_get_context; + +%rename(pn_link_set_context) wrap_pn_link_set_context; +%inline { + void wrap_pn_link_set_context(pn_link_t *l, PyObject *context) { + // don't incref context: we 'borrow' the reference + pn_link_set_context(l, context); + } +} +%ignore pn_link_set_context; + +%rename(pn_delivery_get_context) wrap_pn_delivery_get_context; +%inline { + PyObject *wrap_pn_delivery_get_context(pn_delivery_t *d) { + PyObject *result = (PyObject *) pn_delivery_get_context(d); + // incref the returned context, as the caller expects this + if (result) { + Py_INCREF(result); + return result; + } else { + Py_RETURN_NONE; + } + } +} +%ignore pn_delivery_get_context; + +%rename(pn_delivery_set_context) wrap_pn_delivery_set_context; +%inline { + void wrap_pn_delivery_set_context(pn_delivery_t *d, PyObject *context) { + // don't incref context: we 'borrow' the reference + pn_delivery_set_context(d, context); + } +} +%ignore pn_delivery_set_context; + +ssize_t pn_data_decode(pn_data_t *data, char *STRING, size_t LENGTH); +%ignore pn_data_decode; + +%rename(pn_data_encode) wrap_pn_data_encode; +%inline %{ + int wrap_pn_data_encode(pn_data_t *data, char *OUTPUT, size_t *OUTPUT_SIZE) { + ssize_t sz = pn_data_encode(data, OUTPUT, *OUTPUT_SIZE); + if (sz >= 0) { + *OUTPUT_SIZE = sz; + } else { + *OUTPUT_SIZE = 0; + } + return sz; + } +%} +%ignore pn_data_encode; + +%rename(pn_sasl_recv) wrap_pn_sasl_recv; +%inline %{ + int wrap_pn_sasl_recv(pn_sasl_t *sasl, char *OUTPUT, size_t *OUTPUT_SIZE) { + ssize_t sz = pn_sasl_recv(sasl, OUTPUT, *OUTPUT_SIZE); + if (sz >= 0) { + *OUTPUT_SIZE = sz; + } else { + *OUTPUT_SIZE = 0; + } + return sz; + } +%} +%ignore pn_sasl_recv; + +int pn_data_format(pn_data_t *data, char *OUTPUT, size_t *OUTPUT_SIZE); +%ignore pn_data_format; + +bool pn_ssl_get_cipher_name(pn_ssl_t *ssl, char *OUTPUT, size_t MAX_OUTPUT_SIZE); +%ignore pn_ssl_get_cipher_name; + +bool pn_ssl_get_protocol_name(pn_ssl_t *ssl, char *OUTPUT, size_t MAX_OUTPUT_SIZE); +%ignore pn_ssl_get_protocol_name; + +int pn_ssl_get_peer_hostname(pn_ssl_t *ssl, char *OUTPUT, size_t *OUTPUT_SIZE); +%ignore pn_ssl_get_peer_hostname; + + +%include "proton/cproton.i" http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/python/proton.py ---------------------------------------------------------------------- diff --git a/proton-c/bindings/python/proton.py b/proton-c/bindings/python/proton.py index 12da599..7294d45 100644 --- a/proton-c/bindings/python/proton.py +++ b/proton-c/bindings/python/proton.py @@ -464,6 +464,7 @@ first message. sub_impl = pn_messenger_subscribe(self._mng, source) if not sub_impl: self._check(pn_error_code(pn_messenger_error(self._mng))) + raise MessengerException("Cannot subscribe to %s"%source) return Subscription(sub_impl) def put(self, message): @@ -760,8 +761,7 @@ first message. return None class Message(object): - """ - The L{Message} class is a mutable holder of message content. + """The L{Message} class is a mutable holder of message content. @ivar instructions: delivery instructions for the message @type instructions: dict @@ -780,7 +780,10 @@ class Message(object): DEFAULT_PRIORITY = PN_DEFAULT_PRIORITY - def __init__(self): + def __init__(self, **kwargs): + """ + @param kwargs: Message property name/value pairs to initialise the Message + """ self._msg = pn_message() self._id = Data(pn_message_id(self._msg)) self._correlation_id = Data(pn_message_correlation_id(self._msg)) @@ -788,6 +791,9 @@ class Message(object): self.annotations = None self.properties = None self.body = None + for k,v in kwargs.iteritems(): + getattr(self, k) # Raise exception if it's not a valid attribute. + setattr(self, k, v) def __del__(self): if hasattr(self, "_msg"): @@ -860,7 +866,14 @@ class Message(object): def _set_inferred(self, value): self._check(pn_message_set_inferred(self._msg, bool(value))) - inferred = property(_is_inferred, _set_inferred) + inferred = property(_is_inferred, _set_inferred,""" +The inferred flag for a message indicates how the message content +is encoded into AMQP sections. If inferred is true then binary and +list values in the body of the message will be encoded as AMQP DATA +and AMQP SEQUENCE sections, respectively. If inferred is false, +then all values in the body of the message will be encoded as AMQP +VALUE sections regardless of their type. +""") def _is_durable(self): return pn_message_is_durable(self._msg) @@ -2165,6 +2178,16 @@ class Endpoint(object): def __init__(self): self.condition = None + self._release_invoked = False + + def _release(self): + """Release the underlying C Engine resource.""" + if not self._release_invoked: + for c in self._children: + c._release() + self._free_resource() + self.connection._releasing(self) + self._release_invoked = True def _update_cond(self): obj2cond(self.condition, self._get_cond_impl()) @@ -2256,13 +2279,32 @@ class Connection(Endpoint): def __del__(self): if hasattr(self, "_conn") and self._conn: - # pn_connection_free will release all child sessions in the C Engine, so - # free all child python Sessions to avoid dangling references - if hasattr(self, "_sessions") and self._sessions: - for s in self._sessions: - s._release() - pn_connection_set_context(self._conn, None) - pn_connection_free(self._conn) + self._release() + + def free(self): + self._release() + + @property + def _children(self): + return self._sessions + + @property + def connection(self): + return self + + def _free_resource(self): + pn_connection_free(self._conn) + + def _released(self): + self._conn = None + + def _releasing(self, child): + coll = getattr(self, "_collector", None) + if coll: coll = coll() + if coll: + coll._contexts.add(child) + else: + child._released() def _check(self, err): if err < 0: @@ -2282,9 +2324,7 @@ class Connection(Endpoint): pn_connection_collect(self._conn, None) else: pn_connection_collect(self._conn, collector._impl) - # XXX: we can't let coll go out of scope or the connection will be - # pointing to garbage - self._collector = collector + self._collector = weakref.ref(collector) def _get_container(self): return pn_connection_get_container(self._conn) @@ -2376,16 +2416,15 @@ class Session(Endpoint): self._links = set() self.connection._sessions.add(self) - def _release(self): - """Release the underlying C Engine resource.""" - if self._ssn: - # pn_session_free will release all child links in the C Engine, so free - # all child python Links to avoid dangling references - for l in self._links: - l._release() - pn_session_set_context(self._ssn, None) - pn_session_free(self._ssn) - self._ssn = None + @property + def _children(self): + return self._links + + def _free_resource(self): + pn_session_free(self._ssn) + + def _released(self): + self._ssn = None def free(self): """Release the Session, freeing its resources. @@ -2477,16 +2516,15 @@ class Link(Endpoint): self._deliveries = set() self.session._links.add(self) - def _release(self): - """Release the underlying C Engine resource.""" - if self._link: - # pn_link_free will settle all child deliveries in the C Engine, so free - # all child python deliveries to avoid dangling references - for d in self._deliveries: - d._release() - pn_link_set_context(self._link, None) - pn_link_free(self._link) - self._link = None + @property + def _children(self): + return self._deliveries + + def _free_resource(self): + pn_link_free(self._link) + + def _released(self): + self._link = None def free(self): """Release the Link, freeing its resources""" @@ -2536,6 +2574,10 @@ class Link(Endpoint): def session(self): return Session._wrap_session(pn_link_session(self._link)) + @property + def connection(self): + return self.session.connection + def delivery(self, tag): return Delivery._wrap_delivery(pn_delivery(self._link, tag)) @@ -2719,13 +2761,38 @@ class Receiver(Link): def draining(self): return pn_link_draining(self._link) +class NamedInt(int): + + values = {} + + def __new__(cls, i, name): + ni = super(NamedInt, cls).__new__(cls, i) + cls.values[i] = ni + return ni + + def __init__(self, i, name): + self.name = name + + def __repr__(self): + return self.name + + def __str__(self): + return self.name + + @classmethod + def get(cls, i): + return cls.values.get(i, i) + +class DispositionType(NamedInt): + values = {} + class Disposition(object): - RECEIVED = PN_RECEIVED - ACCEPTED = PN_ACCEPTED - REJECTED = PN_REJECTED - RELEASED = PN_RELEASED - MODIFIED = PN_MODIFIED + RECEIVED = DispositionType(PN_RECEIVED, "RECEIVED") + ACCEPTED = DispositionType(PN_ACCEPTED, "ACCEPTED") + REJECTED = DispositionType(PN_REJECTED, "REJECTED") + RELEASED = DispositionType(PN_RELEASED, "RELEASED") + MODIFIED = DispositionType(PN_MODIFIED, "MODIFIED") def __init__(self, impl, local): self._impl = impl @@ -2736,7 +2803,7 @@ class Disposition(object): @property def type(self): - return pn_disposition_type(self._impl) + return DispositionType.get(pn_disposition_type(self._impl)) def _get_section_number(self): return pn_disposition_get_section_number(self._impl) @@ -2824,12 +2891,13 @@ class Delivery(object): self.remote = Disposition(pn_delivery_remote(self._dlv), False) self.link._deliveries.add(self) + def __del__(self): + pn_delivery_set_context(self._dlv, None) + def _release(self): """Release the underlying C Engine resource.""" if self._dlv: - pn_delivery_set_context(self._dlv, None) pn_delivery_settle(self._dlv) - self._dlv = None @property def tag(self): @@ -2863,11 +2931,11 @@ class Delivery(object): @property def local_state(self): - return pn_delivery_local_state(self._dlv) + return DispositionType.get(pn_delivery_local_state(self._dlv)) @property def remote_state(self): - return pn_delivery_remote_state(self._dlv) + return DispositionType.get(pn_delivery_remote_state(self._dlv)) @property def settled(self): @@ -2891,6 +2959,7 @@ class TransportException(ProtonException): class Transport(object): + TRACE_OFF = PN_TRACE_OFF TRACE_DRV = PN_TRACE_DRV TRACE_FRM = PN_TRACE_FRM TRACE_RAW = PN_TRACE_RAW @@ -2955,7 +3024,9 @@ class Transport(object): return self._check(c) def push(self, bytes): - self._check(pn_transport_push(self._trans, bytes)) + n = self._check(pn_transport_push(self._trans, bytes)) + if n != len(bytes): + raise OverflowError("unable to process all bytes") def close_tail(self): self._check(pn_transport_close_tail(self._trans)) @@ -2981,26 +3052,9 @@ class Transport(object): def close_head(self): self._check(pn_transport_close_head(self._trans)) - def output(self, size): - p = self.pending() - if p < 0: - return None - else: - out = self.peek(min(size, p)) - self.pop(len(out)) - return out - - def input(self, bytes): - if not bytes: - self.close_tail() - return None - else: - c = self.capacity() - if (c < 0): - return None - trimmed = bytes[:c] - self.push(trimmed) - return len(trimmed) + @property + def closed(self): + return pn_transport_closed(self._trans) # AMQP 1.0 max-frame-size def _get_max_frame_size(self): @@ -3078,6 +3132,7 @@ class SASL(object): OK = PN_SASL_OK AUTH = PN_SASL_AUTH + SKIPPED = PN_SASL_SKIPPED def __new__(cls, transport): """Enforce a singleton SASL object per Transport""" @@ -3103,6 +3158,9 @@ class SASL(object): def server(self): pn_sasl_server(self._sasl) + def allow_skip(self, allow): + pn_sasl_allow_skip(self._sasl, allow) + def plain(self, user, password): pn_sasl_plain(self._sasl, user, password) @@ -3265,6 +3323,7 @@ class Collector: def __init__(self): self._impl = pn_collector() + self._contexts = set() def peek(self): event = pn_collector_peek(self._impl) @@ -3285,6 +3344,9 @@ class Collector: transport=tp) def pop(self): + ev = self.peek() + if ev is not None: + ev._popped(self) pn_collector_pop(self._impl) def __del__(self): @@ -3292,15 +3354,34 @@ class Collector: class Event: - CATEGORY_PROTOCOL = PN_EVENT_CATEGORY_PROTOCOL - - CONNECTION_LOCAL_STATE = PN_CONNECTION_LOCAL_STATE - CONNECTION_REMOTE_STATE = PN_CONNECTION_REMOTE_STATE - SESSION_LOCAL_STATE = PN_SESSION_LOCAL_STATE - SESSION_REMOTE_STATE = PN_SESSION_REMOTE_STATE - LINK_LOCAL_STATE = PN_LINK_LOCAL_STATE - LINK_REMOTE_STATE = PN_LINK_REMOTE_STATE + CATEGORY_CONNECTION = PN_EVENT_CATEGORY_CONNECTION + CATEGORY_SESSION = PN_EVENT_CATEGORY_SESSION + CATEGORY_LINK = PN_EVENT_CATEGORY_LINK + CATEGORY_DELIVERY = PN_EVENT_CATEGORY_DELIVERY + CATEGORY_TRANSPORT = PN_EVENT_CATEGORY_TRANSPORT + + CONNECTION_INIT = PN_CONNECTION_INIT + CONNECTION_OPEN = PN_CONNECTION_OPEN + CONNECTION_CLOSE = PN_CONNECTION_CLOSE + CONNECTION_REMOTE_OPEN = PN_CONNECTION_REMOTE_OPEN + CONNECTION_REMOTE_CLOSE = PN_CONNECTION_REMOTE_CLOSE + CONNECTION_FINAL = PN_CONNECTION_FINAL + + SESSION_INIT = PN_SESSION_INIT + SESSION_OPEN = PN_SESSION_OPEN + SESSION_CLOSE = PN_SESSION_CLOSE + SESSION_REMOTE_OPEN = PN_SESSION_REMOTE_OPEN + SESSION_REMOTE_CLOSE = PN_SESSION_REMOTE_CLOSE + SESSION_FINAL = PN_SESSION_FINAL + + LINK_INIT = PN_LINK_INIT + LINK_OPEN = PN_LINK_OPEN + LINK_CLOSE = PN_LINK_CLOSE + LINK_REMOTE_OPEN = PN_LINK_REMOTE_OPEN + LINK_REMOTE_CLOSE = PN_LINK_REMOTE_CLOSE LINK_FLOW = PN_LINK_FLOW + LINK_FINAL = PN_LINK_FINAL + DELIVERY = PN_DELIVERY TRANSPORT = PN_TRANSPORT @@ -3314,6 +3395,19 @@ class Event: self.delivery = delivery self.transport = transport + def _popped(self, collector): + if self.type == Event.LINK_FINAL: + ctx = self.link + elif self.type == Event.SESSION_FINAL: + ctx = self.session + elif self.type == Event.CONNECTION_FINAL: + ctx = self.connection + else: + return + + collector._contexts.remove(ctx) + ctx._released() + def __repr__(self): objects = [self.connection, self.session, self.link, self.delivery, self.transport] @@ -3544,6 +3638,8 @@ __all__ = [ "Messenger", "MessengerException", "ProtonException", + "PN_VERSION_MAJOR", + "PN_VERSION_MINOR", "Receiver", "SASL", "Sender", http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/1c2f4894/proton-c/bindings/python/python.i ---------------------------------------------------------------------- diff --git a/proton-c/bindings/python/python.i b/proton-c/bindings/python/python.i deleted file mode 100644 index 878b34c..0000000 --- a/proton-c/bindings/python/python.i +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -%module cproton -%{ -/* Includes the header in the wrapper code */ -#if defined(_WIN32) && ! defined(__CYGWIN__) -#include <winsock2.h> -#endif -#include <proton/engine.h> -#include <proton/message.h> -#include <proton/sasl.h> -#include <proton/driver.h> -#include <proton/driver_extras.h> -#include <proton/messenger.h> -#include <proton/ssl.h> -%} - -%include <cstring.i> - -%cstring_output_withsize(char *OUTPUT, size_t *OUTPUT_SIZE) -%cstring_output_allocate_size(char **ALLOC_OUTPUT, size_t *ALLOC_SIZE, free(*$1)); -%cstring_output_maxsize(char *OUTPUT, size_t MAX_OUTPUT_SIZE) - -%typemap(in) pn_bytes_t { - if ($input == Py_None) { - $1.start = NULL; - $1.size = 0; - } else { - $1.start = PyString_AsString($input); - if (!$1.start) { - return NULL; - } - $1.size = PyString_Size($input); - } -} - -%typemap(out) pn_bytes_t { - $result = PyString_FromStringAndSize($1.start, $1.size); -} - -%typemap(in) pn_decimal128_t { - memmove($1.bytes, PyString_AsString($input), 16); -} - -%typemap(out) pn_decimal128_t { - $result = PyString_FromStringAndSize($1.bytes, 16); -} - -%typemap(in) pn_uuid_t { - memmove($1.bytes, PyString_AsString($input), 16); -} - -%typemap(out) pn_uuid_t { - $result = PyString_FromStringAndSize($1.bytes, 16); -} - -int pn_message_load(pn_message_t *msg, char *STRING, size_t LENGTH); -%ignore pn_message_load; - -int pn_message_load_data(pn_message_t *msg, char *STRING, size_t LENGTH); -%ignore pn_message_load_data; - -int pn_message_load_text(pn_message_t *msg, char *STRING, size_t LENGTH); -%ignore pn_message_load_text; - -int pn_message_load_amqp(pn_message_t *msg, char *STRING, size_t LENGTH); -%ignore pn_message_load_amqp; - -int pn_message_load_json(pn_message_t *msg, char *STRING, size_t LENGTH); -%ignore pn_message_load_json; - -int pn_message_encode(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE); -%ignore pn_message_encode; - -int pn_message_save(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE); -%ignore pn_message_save; - -int pn_message_save_data(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE); -%ignore pn_message_save_data; - -int pn_message_save_text(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE); -%ignore pn_message_save_text; - -int pn_message_save_amqp(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE); -%ignore pn_message_save_amqp; - -int pn_message_save_json(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE); -%ignore pn_message_save_json; - -ssize_t pn_link_send(pn_link_t *transport, char *STRING, size_t LENGTH); -%ignore pn_link_send; - -%rename(pn_link_recv) wrap_pn_link_recv; -%inline %{ - int wrap_pn_link_recv(pn_link_t *link, char *OUTPUT, size_t *OUTPUT_SIZE) { - ssize_t sz = pn_link_recv(link, OUTPUT, *OUTPUT_SIZE); - if (sz >= 0) { - *OUTPUT_SIZE = sz; - } else { - *OUTPUT_SIZE = 0; - } - return sz; - } -%} -%ignore pn_link_recv; - -int pn_transport_push(pn_transport_t *transport, char *STRING, size_t LENGTH); -%ignore pn_transport_push; - -%rename(pn_transport_peek) wrap_pn_transport_peek; -%inline %{ - int wrap_pn_transport_peek(pn_transport_t *transport, char *OUTPUT, size_t *OUTPUT_SIZE) { - return pn_transport_peek(transport, OUTPUT, *OUTPUT_SIZE); - } -%} -%ignore pn_transport_peek; - -ssize_t pn_transport_input(pn_transport_t *transport, char *STRING, size_t LENGTH); -%ignore pn_transport_input; - -%rename(pn_transport_output) wrap_pn_transport_output; -%inline %{ - int wrap_pn_transport_output(pn_transport_t *transport, char *OUTPUT, size_t *OUTPUT_SIZE) { - ssize_t sz = pn_transport_output(transport, OUTPUT, *OUTPUT_SIZE); - if (sz >= 0) { - *OUTPUT_SIZE = sz; - } else { - *OUTPUT_SIZE = 0; - } - return sz; - } -%} -%ignore pn_transport_output; - -%rename(pn_delivery) wrap_pn_delivery; -%inline %{ - pn_delivery_t *wrap_pn_delivery(pn_link_t *link, char *STRING, size_t LENGTH) { - return pn_delivery(link, pn_dtag(STRING, LENGTH)); - } -%} -%ignore pn_delivery; - -// Suppress "Warning(451): Setting a const char * variable may leak memory." on pn_delivery_tag_t -%warnfilter(451) pn_delivery_tag_t; -%rename(pn_delivery_tag) wrap_pn_delivery_tag; -%inline %{ - void wrap_pn_delivery_tag(pn_delivery_t *delivery, char **ALLOC_OUTPUT, size_t *ALLOC_SIZE) { - pn_delivery_tag_t tag = pn_delivery_tag(delivery); - *ALLOC_OUTPUT = (char *) malloc(tag.size); - *ALLOC_SIZE = tag.size; - memcpy(*ALLOC_OUTPUT, tag.bytes, tag.size); - } -%} -%ignore pn_delivery_tag; - -%rename(pn_message_data) wrap_pn_message_data; -%inline %{ - int wrap_pn_message_data(char *STRING, size_t LENGTH, char *OUTPUT, size_t *OUTPUT_SIZE) { - ssize_t sz = pn_message_data(OUTPUT, *OUTPUT_SIZE, STRING, LENGTH); - if (sz >= 0) { - *OUTPUT_SIZE = sz; - } else { - *OUTPUT_SIZE = 0; - } - return sz; - } -%} -%ignore pn_message_data; - -%rename(pn_listener_set_context) wrap_pn_listener_set_context; -%inline { - void wrap_pn_listener_set_context(pn_listener_t *l, PyObject *context) { - // don't incref context: we 'borrow' the reference - prevents - // reference loops. Should be safe as the Python object must - // outlive the C object. - pn_listener_set_context(l, context); - } -} -%ignore pn_listener_set_context; - -%rename(pn_listener_context) wrap_pn_listener_context; -%inline { - PyObject *wrap_pn_listener_context(pn_listener_t *l) { - PyObject *result = (PyObject *) pn_listener_context(l); - // incref the returned context, as the caller expects this - if (result) { - Py_INCREF(result); - return result; - } else { - Py_RETURN_NONE; - } - } -} -%ignore pn_listener_context; - -%rename(pn_connector_set_context) wrap_pn_connector_set_context; -%inline { - void wrap_pn_connector_set_context(pn_connector_t *c, PyObject *context) { - // don't incref context: we 'borrow' the reference - prevents - // reference loops. Should be safe as the Python object must - // outlive the C object. - pn_connector_set_context(c, context); - } -} -%ignore pn_connector_set_context; - -%rename(pn_connector_context) wrap_pn_connector_context; -%inline { - PyObject *wrap_pn_connector_context(pn_connector_t *c) { - PyObject *result = (PyObject *) pn_connector_context(c); - // incref the returned context, as the caller expects this - if (result) { - Py_INCREF(result); - return result; - } else { - Py_RETURN_NONE; - } - } -} -%ignore pn_connector_context; - -%rename(pn_connection_get_context) wrap_pn_connection_get_context; -%inline { - PyObject *wrap_pn_connection_get_context(pn_connection_t *c) { - PyObject *result = (PyObject *) pn_connection_get_context(c); - // incref the returned context, as the caller expects this - if (result) { - Py_INCREF(result); - return result; - } else { - Py_RETURN_NONE; - } - } -} -%ignore pn_connection_get_context; - -%rename(pn_connection_set_context) wrap_pn_connection_set_context; -%inline { - void wrap_pn_connection_set_context(pn_connection_t *c, PyObject *context) { - // don't incref context: we 'borrow' the reference - pn_connection_set_context(c, context); - } -} -%ignore pn_connection_set_context; - -%rename(pn_session_get_context) wrap_pn_session_get_context; -%inline { - PyObject *wrap_pn_session_get_context(pn_session_t *s) { - PyObject *result = (PyObject *) pn_session_get_context(s); - // incref the returned context, as the caller expects this - if (result) { - Py_INCREF(result); - return result; - } else { - Py_RETURN_NONE; - } - } -} -%ignore pn_session_get_context; - -%rename(pn_session_set_context) wrap_pn_session_set_context; -%inline { - void wrap_pn_session_set_context(pn_session_t *s, PyObject *context) { - // don't incref context: we 'borrow' the reference - pn_session_set_context(s, context); - } -} -%ignore pn_session_set_context; - -%rename(pn_link_get_context) wrap_pn_link_get_context; -%inline { - PyObject *wrap_pn_link_get_context(pn_link_t *l) { - PyObject *result = (PyObject *) pn_link_get_context(l); - // incref the returned context, as the caller expects this - if (result) { - Py_INCREF(result); - return result; - } else { - Py_RETURN_NONE; - } - } -} -%ignore pn_link_get_context; - -%rename(pn_link_set_context) wrap_pn_link_set_context; -%inline { - void wrap_pn_link_set_context(pn_link_t *l, PyObject *context) { - // don't incref context: we 'borrow' the reference - pn_link_set_context(l, context); - } -} -%ignore pn_link_set_context; - -%rename(pn_delivery_get_context) wrap_pn_delivery_get_context; -%inline { - PyObject *wrap_pn_delivery_get_context(pn_delivery_t *d) { - PyObject *result = (PyObject *) pn_delivery_get_context(d); - // incref the returned context, as the caller expects this - if (result) { - Py_INCREF(result); - return result; - } else { - Py_RETURN_NONE; - } - } -} -%ignore pn_delivery_get_context; - -%rename(pn_delivery_set_context) wrap_pn_delivery_set_context; -%inline { - void wrap_pn_delivery_set_context(pn_delivery_t *d, PyObject *context) { - // don't incref context: we 'borrow' the reference - pn_delivery_set_context(d, context); - } -} -%ignore pn_delivery_set_context; - -ssize_t pn_data_decode(pn_data_t *data, char *STRING, size_t LENGTH); -%ignore pn_data_decode; - -%rename(pn_data_encode) wrap_pn_data_encode; -%inline %{ - int wrap_pn_data_encode(pn_data_t *data, char *OUTPUT, size_t *OUTPUT_SIZE) { - ssize_t sz = pn_data_encode(data, OUTPUT, *OUTPUT_SIZE); - if (sz >= 0) { - *OUTPUT_SIZE = sz; - } else { - *OUTPUT_SIZE = 0; - } - return sz; - } -%} -%ignore pn_data_encode; - -%rename(pn_sasl_recv) wrap_pn_sasl_recv; -%inline %{ - int wrap_pn_sasl_recv(pn_sasl_t *sasl, char *OUTPUT, size_t *OUTPUT_SIZE) { - ssize_t sz = pn_sasl_recv(sasl, OUTPUT, *OUTPUT_SIZE); - if (sz >= 0) { - *OUTPUT_SIZE = sz; - } else { - *OUTPUT_SIZE = 0; - } - return sz; - } -%} -%ignore pn_sasl_recv; - -int pn_data_format(pn_data_t *data, char *OUTPUT, size_t *OUTPUT_SIZE); -%ignore pn_data_format; - -bool pn_ssl_get_cipher_name(pn_ssl_t *ssl, char *OUTPUT, size_t MAX_OUTPUT_SIZE); -%ignore pn_ssl_get_cipher_name; - -bool pn_ssl_get_protocol_name(pn_ssl_t *ssl, char *OUTPUT, size_t MAX_OUTPUT_SIZE); -%ignore pn_ssl_get_protocol_name; - -int pn_ssl_get_peer_hostname(pn_ssl_t *ssl, char *OUTPUT, size_t *OUTPUT_SIZE); -%ignore pn_ssl_get_peer_hostname; - - -%include "proton/cproton.i" --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
