Back to index

plone3  3.1.7
message.py
Go to the documentation of this file.
00001 import struct
00002 
00003 from zope.interface import implements
00004 
00005 from Products.statusmessages.interfaces import IMessage
00006 
00007 
00008 def _utf8(value):
00009     if isinstance(value, unicode):
00010         return value.encode('utf-8')
00011     elif isinstance(value, str):
00012         return value
00013     return ''
00014 
00015 def _unicode(value):
00016     return unicode(value, 'utf-8', 'ignore')
00017 
00018 
00019 class Message:
00020     """A single status message.
00021 
00022     Let's make sure that this implementation actually fulfills the
00023     'IMessage' API.
00024 
00025       >>> from zope.interface.verify import verifyClass
00026       >>> verifyClass(IMessage, Message)
00027       True
00028     
00029       >>> status = Message(u'this is a test', type=u'info')
00030       >>> status.message
00031       u'this is a test'
00032 
00033       >>> status.type
00034       u'info'
00035 
00036     It is quite common to use MessageID's as status messages:
00037 
00038       >>> from zope.i18nmessageid import MessageFactory
00039       >>> from zope.i18nmessageid import Message as I18NMessage
00040       >>> msg_factory = MessageFactory('test')
00041 
00042       >>> msg = msg_factory(u'test_message', default=u'Default text')
00043 
00044       >>> status = Message(msg, type=u'warn')
00045       >>> status.type
00046       u'warn'
00047 
00048       >>> type(status.message) is I18NMessage
00049       True
00050 
00051       >>> status.message.default
00052       u'Default text'
00053 
00054       >>> status.message.domain
00055       'test'
00056 
00057     """
00058     implements(IMessage)
00059 
00060     def __init__(self, message, type=''):
00061         self.message = message
00062         self.type = type
00063 
00064     def __eq__(self, other):
00065         if not isinstance(other, Message):
00066             return False
00067         if self.message == other.message and self.type == other.type:
00068             return True
00069         return False
00070 
00071     def encode(self):
00072         """
00073         Encode to a cookie friendly format.
00074         
00075         The format consists of a two bytes length header of 11 bits for the
00076         message length and 5 bits for the type length followed by two values.
00077         """
00078         message = _utf8(self.message)[:0x3FF] # we can store 2^11 bytes
00079         type = _utf8(self.type)[:0x1F]        # we can store 2^5 bytes
00080         size = (len(message) << 5) + (len(type) & 31) # pack into 16 bits
00081         
00082         return struct.pack('!H%ds%ds' % (len(message), len(type)), 
00083                            size, message, type)
00084 
00085 def decode(value):
00086     """
00087     Decode messages from a cookie
00088 
00089     We return the decoded message object, and the remainder of the cookie
00090     value (it can contain further messages).
00091 
00092     We expect at least 2 bytes (size information).
00093     """
00094     if len(value) >= 2:
00095         size = struct.unpack('!H', value[:2])[0]
00096         msize, tsize = (size >> 5, size & 31)
00097         message = Message(_unicode(value[2:msize+2]),
00098                           _unicode(value[msize+2:msize+tsize+2]))
00099         return message, value[msize+tsize+2:]
00100     return None, ''