SlideShare a Scribd company logo
1 of 42
Download to read offline
ERGroupware
Pascal Robert
Druide informatique
• Let you generate iCalendar files, à la ERCalendar
• Let you connect to groupware solutions
• CalDAV
• MS Exchange 2007/2010
• Zimbra
• Many Bothans have died to provide this framework
What is ERGroupware?
iCalendar generation
iCalendar
• iCalendar is a standard (RFC 2445, written in 1998).
• A iCalendar object can have multiple components (VEVENT,
VTODO, etc.)
• Text file, with Base64 encoding for binary
• Key value
• You can add your own keys
iCalendar example
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//Mac OS X 10.8.4//EN
CALSCALE:GREGORIAN
BEGIN:VEVENT
TRANSP:OPAQUE
DTEND:20130623T101500
UID:DB0E22EA-0828-40A3-BCFD-5A8CC9866CE4
DTSTAMP:20130514T135551Z
LOCATION:Verdun/Lachine/Lasalle
X-MOZ-GENERATION:1
URL;VALUE=URI:http://www.wocommunity.org/wowodc13/cayenne.html
SEQUENCE:10
SUMMARY:Cayenne Training Day
LAST-MODIFIED:20130509T165550Z
DTSTART:20130623T091500
CREATED:20130505T001152Z
END:VEVENT
END:VCALENDAR
UID
• Each component must have a UID
• UID:DB0E22EA-0828-40A3-BCFD-5A8CC9866CE4
• And it must be unique!
Attendees
• Attendees are invitees.
• Can be a individual, group, resource or room. (CUType)
• Also have status: needs action, accepted, etc. (Partstat)
• If you have attendees, you also need an organizer!
iCalendar in ERGroupware
• Similar to ERCalendar, but more modern and better validation.
• Using iCal4j, a solid iCalendar library for Java.
• Component to generate the file.
• Will generate a text/calendar response
iCalendar file generation
ERGWCalendar aCalendar = new ERGWCalendar();
ERGWEvent event = new ERGWEvent(aCalendar);
java.util.Calendar startTime = GregorianCalendar.getInstance();
event.setStartTime(new NSTimestamp(startTime.getTimeInMillis()));
java.util.Calendar endTime = GregorianCalendar.getInstance();
endTime.add(java.util.Calendar.HOUR, 2);
event.setEndTime(new NSTimestamp(endTime.getTimeInMillis()));
event.setClassification(ERGWClassification.PUBLIC);
event.setFreeBusyStatus(ERGWFreeBusyStatus.BUSY_TENTATIVE);
event.setLocation("Montreal");
event.setCategories(new NSArray<String>(new String[] { "Category 1", "Category 2" }));
event.setPriority(ERGWPriority.HIGH);
event.setSummary("WOWODC 2013");
event.setTransparency(ERGWTransparency.TRANSPARENT);
Calendar calendarData = ERGWCalendar.transformToICalObject(aCalendar);
ERGWPublishCalendarPage nextPage = (ERGWPublishCalendarPage)pageWithName(ERGWPublishCalendarPage.class);
nextPage.setCalendar(calendarData);
return nextPage;
CalDAV/CardDAV
• Both based on WebDAV
• Will store iCalendar objects (CalDAV) or vCard objects
(CardDAV)
• Many many server implementations
• But some of them are really basic (Google Calendar...)
• iCal Server is the best implementation
• Many clients too
CalDAV
• Open standard, defined in RFC 4791
• Servers must implements this RFC
• Many extensions
• Scheduling
• Delegations
• Sharing
• etc.
CalDAV
• Calendars are DAV collections.
• DAV collections have properties (ACL, owner, etc.).
• Can create as many collections as you want.
• Other DAV collections exists too.
Features/extensions
• CalDAV servers must send the supported features set in the
response.
• Can do a OPTIONS request to see them.
• Check the DAV header in the response.
OPTIONS request
$ curl --digest --user probert -X OPTIONS -v http://localhost:8008
< DAV: 1, access-control, calendar-access, calendar-schedule, calendar-
auto-schedule, calendar-availability, inbox-availability, calendar-
proxy, calendarserver-private-events, calendarserver-private-comments,
calendarserver-sharing, calendarserver-sharing-no-scheduling, calendar-
query-extended, calendar-default-alarms, addressbook, extended-mkcol,
calendarserver-principal-property-search, calendarserver-principal-
search
CalDAV and HTTP
• Almost REST-like
• Use HTTP verbs
• GET: fetch a object
• PUT: create OR update a object
• DELETE: delete a object
• MKCALENDAR: create a calendar collection
• Use headers, HTTP authentication (Basic, Digest, Kerberos...)
iCalendar objects
• You store iCalendar objects in calendar collections.
• But you can only store ONE component (VTODO,VEVENT,
etc.) per object.
PUT
• CalDAV don't use POST to create objects.
• Must use PUT
• If URL and UID already exists, will update the object.
• If URL and UID don't exists, will create the object.
• If URL don't exist but UID exist, will conflict.
• Creating a object will return a 201 status code.
• If you copy an object, don't forget to change the UID.
Example of creating event
PUT /calendars/__uids__/AD04C60B-3704-447B-8997-24F5ACF589C7/calendar/C440-473C-8FAD-D3E606159F40.ics HTTP/1.1
If-None-Match: 1f9e6e30-dfdb-4e5c-baf6-6dd107126a68
Content-Type: text/calendar
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Apple Inc.//Mac OS X 10.8.4//EN
CALSCALE:GREGORIAN
BEGIN:VEVENT
ATTENDEE;CN="probert@macti.ca";CUTYPE=INDIVIDUAL:mailto:probert@macti.ca
ATTENDEE;CN="Pascal Robert";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:urn:uuid:AD04C60B-3704-447B-8997-24F5ACF589C7
DTEND;VALUE=DATE:20130616
TRANSP:TRANSPARENT
ORGANIZER;CN="Pascal Robert":urn:uuid:AD04C60B-3704-447B-8997-24F5ACF589C7
UID:B54100D2-C440-473C-8FAD-D3E606159F40
DTSTAMP:20130615T123551Z
LOCATION:Hilton Montréal Bonaventure
SEQUENCE:9
SUMMARY:Test for presentation
DTSTART;VALUE=DATE:20130615
CREATED:20130615T123241Z
END:VEVENT
END:VCALENDAR
CalDAV support in ERGroupware
• Based on iCal4j-connector, which I contributed to.
• Support for most CalDAV operations.
• Get calendars (collections)
• Create calendars
• Fetch/delete/update calendar objects
• Delete collections
• Fetch events by time-range
Connecting
import net.fortuna.ical4j.connector.ObjectStoreException;
import net.fortuna.ical4j.connector.dav.PathResolver;
import er.groupware.caldav.CalDAVStore;
import java.net.URL;
CalDAVStore store = null;
try {
store = new CalDAVStore("probert", "somepassword", new URL("http://127.0.0.1"),
PathResolver.ICAL_SERVER);
}
catch (MalformedURLException e) {
e.printStackTrace();
}
catch (ObjectStoreException e) {
e.printStackTrace();
}
Fetching calendar collections and objects
NSArray<CalDAVCollection> collections = store.getCollections();
for (CalDAVCollection collection: collections) {
NSLog.out.appendln(collection.displayName());
// Fetch all events (e.g, VEVENT objects)
NSArray<ERGWCalendar> events = collection.events();
// Fetch all tasks (e.g, VTOTO objects)
NSArray<ERGWCalendar> tasks = collection.tasks();
}
Manipuling calendar objects
// Create a new event and send it to the server
ERGWCalendar aCalendar = new ERGWCalendar();
ERGWEvent event = new ERGWEvent(aCalendar);
java.util.Calendar startTime = GregorianCalendar.getInstance();
event.setStartTime(new NSTimestamp(startTime.getTimeInMillis()));
java.util.Calendar endTime = GregorianCalendar.getInstance();
endTime.add(java.util.Calendar.HOUR, 2);
event.setEndTime(new NSTimestamp(endTime.getTimeInMillis()));
event.setSummary("WOWODC 2013");
collection.addCalendarObject(aCalendar);
// Update the event and send it to the server
aCalendar.events().objectAtIndex(0).setSummary("WOWODC 2014");
collection.updateCalendarObject(aCalendar);
// Delete the event
collection.removeCalendarObject(aCalendar.events().objectAtIndex(0));
Queries
• REPORT request is the same idea as a SQL SELECT query.
• Let's you find calendar objects with a qualifier.
• "Find all todos that are completed"
• "Find events from June 22 to June 24"
• "Find all rooms"
• Won't work for custom properties
Find events by time range
REPORT /bernard/work/ HTTP/1.1
Depth: 1
Content-Type: application/xml; charset="utf-8"
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop>
<C:calendar-data>
<C:limit-recurrence-set start="20060103T000000Z" end="20060105T000000Z"/>
</C:calendar-data>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:time-range start="20060103T000000Z" end="20060105T000000Z"/>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
Find participants that didn't not accept invitations
REPORT /bernard/work/ HTTP/1.1
Depth: 1
Content-Type: application/xml; charset="utf-8"
<?xml version="1.0" encoding="utf-8" ?>
<C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav">
<D:prop xmlns:D="DAV:">
<D:getetag/>
<C:calendar-data/>
</D:prop>
<C:filter>
<C:comp-filter name="VCALENDAR">
<C:comp-filter name="VEVENT">
<C:prop-filter name="ATTENDEE">
<C:param-filter name="PARTSTAT">
<C:text-match collation="i;ascii-casemap">NEEDS-ACTION</C:text-match>
</C:param-filter>
</C:prop-filter>
</C:comp-filter>
</C:comp-filter>
</C:filter>
</C:calendar-query>
Queries support in ERGroupware
• Query by time range
• CalDavCollection.eventsForTimePeriod(java.util.Date startTime,
java.util.Date endTime)
• Find all individuals
• store.getIndividuals(String name);
• Find rooms or resources
• store.getAllRooms()
• store.getAllResources()
DEMO
MS Exchange
• Exchange Web Service (EWS)
• Based on SOAP
• Same protocol that Outlook 2011 uses
• Most EWS attributes are similar to iCalendar and DAV
collections attributes
Example of request
---[HTTP request - https://webmail.sherweb2010.com/EWS/Exchange.asmx]---
Content-type: text/xml;charset="utf-8"
Soapaction: "http://schemas.microsoft.com/exchange/services/2006/messages/SyncFolderHierarchy"
Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Header>
<MailboxCulture xmlns="..." xmlns:ns2="...">en-US</MailboxCulture>
<RequestServerVersion xmlns="..." xmlns:ns2="..." Version="Exchange2007_SP1"/>
</S:Header>
<S:Body>
<ns2:SyncFolderHierarchy xmlns="..." xmlns:ns2="...">
<ns2:FolderShape>
<BaseShape>IdOnly</BaseShape>
<AdditionalProperties>
<FieldURI FieldURI="folder:DisplayName"/>
<FieldURI FieldURI="folder:FolderClass"/>
<ExtendedFieldURI PropertyType="Boolean" PropertyTag="0x10F4"/>
</AdditionalProperties>
</ns2:FolderShape>
</ns2:SyncFolderHierarchy>
</S:Body>
</S:Envelope>
Example of response
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:ServerVersionInfo ... Version="Exchange2010_SP2" />
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<m:SyncFolderHierarchyResponse xmlns:m="..." xmlns:t="..."><m:ResponseMessages>
<m:SyncFolderHierarchyResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:SyncState>H4sIAAAAAAAEAO29B2AcSZYlJi9tynt...</m:SyncState>
<m:Changes>
<t:Create>
<t:Folder>
<t:FolderId Id="AAMkAGEw...=" ChangeKey="AQAAABYAAACT3PaCL/2ASLnqcq9Sv0/DAAAAp5Bv"/>
<t:FolderClass>IPF.Note</t:FolderClass>
<t:DisplayName>INBOX</t:DisplayName>
<t:ExtendedProperty>
<t:ExtendedFieldURI PropertyTag="0x10f4" PropertyType="Boolean"/>
<t:Value>false</t:Value>
</t:ExtendedProperty>
</t:Folder>
</t:Create>
</m:Changes>
...
EWS support in ERGroupware
• Generated with JAXB.
• Very basic support outside the generated classes:
• Open connection
• Create folders
• Create task
• Create contact
• Create event
Opening a connection and fetch folders
URL urlToWSDL = ERXApplication.application().resourceManager().pathURLForResourceNamed("Services.wsdl",
"ERGroupware", null);
ExchangeStore store = new ExchangeStore(urlToWSDL, "https://myserver/EWS/Exchange.asmx", "aUser",
"aPassword", "AD.DOMAIN");
store.setServerVersionForRequest(ExchangeVersionType.EXCHANGE_2010_SP_1);
store.setTimeZone(TimeZone.getDefault());
NSArray<ExchangeBaseFolder> folders = store.folders();
for (ExchangeBaseFolder folder: folders) {
NSLog.out.appendln(folder.displayName());
}
Adding an event
for (ExchangeBaseFolder folder: store.folders()) {
if (folder.displayName().equals("Calendar")) {
ERGWCalendar calendar = new ERGWCalendar();
calendar.setCalendarName("Test");
calendar.setTimeZone(TimeZone.getDefault());
Calendar later = GregorianCalendar.getInstance();
later.add(Calendar.HOUR_OF_DAY, 1);
event.setEndTime(new NSTimestamp(later.getTime()));
UidGenerator uidGen = new UidGenerator("allo");
event.setUid(uidGen.generateUid().getValue());
ERGWEvent event = new ERGWEvent(calendar);
event.setIsFullDay(false);
event.setStartTime(new NSTimestamp());
event.setSummary("WOWODC 2013");
event.setLastModifiedDate(new NSTimestamp());
calendar.addEvent(event);
exchangeStore.createCalendarEvent(calendar, (ExchangeCalendarFolder) folder);
}
}
Adding an event
for (ExchangeBaseFolder folder: store.folders()) {
if (folder.displayName().equals("Tasks")) {
ERGWCalendar calendar = new ERGWCalendar();
calendar.setCalendarName("Test");
calendar.setTimeZone(TimeZone.getDefault());
Calendar later = GregorianCalendar.getInstance();
later.add(Calendar.HOUR_OF_DAY, 1);
task.setDueDate(new NSTimestamp(later.getTime()));
UidGenerator uidGen = new UidGenerator("allo");
event.setUid(uidGen.generateUid().getValue());
ERGWTask task = new ERGWTask(calendar);
task.setSummary("Finish that presentation");
task.setLastModifiedDate(new NSTimestamp());
calendar.addEvent(event);
exchangeStore.createTask(calendar, (ExchangeCalendarFolder) folder);
}
}
Adding a contact
for (ExchangeBaseFolder folder: store.folders()) {
if (folder.displayName().equals("Contacts")) {
ERGWContact contact = new ERGWContact();
contact.setGivenName("Pascal");
contact.setFamilyName("Robert");
ERGWContactEmail personalEmail = new ERGWContactEmail();
personalEmail.setEmail("probert@macti.ca");
personalEmail.isPrefered(true);
personalEmail.setTypes(new NSArray<ERGWContactEmailType>(new ERGWContactEmailType[]
{ ERGWContactEmailType.HOME }));
contact.setEmails(new NSArray<ERGWContactEmail>(new ERGWContactEmail[] { personalEmail }));
exchangeStore.createContact(contact, (ExchangeCalendarFolder) folder);
}
}
Create folders
// Create a folder of a specific type
// ERGWFolderType values are: CALENDAR, CONTACTS, TASKS, SEARCH, PLAIN, etc.
store.createFolder("New calendar folder", ERGWFolderType.CALENDAR);
store.createFolder("New contacts folder", ERGWFolderType.CONTACTS);
// Shortcut to create a calendar folder
store.createCalendarFolder(String displayName)
// Shortcut to create a contacts folder
store.createContactsFolder(String displayName)
Zimbra
• SOAP and REST-based API.
• Have API for everything: management, data and Web client
(Zimlets).
• Very basic support in ERGroupware (need to migrate a lot of
code)
• Connect to store
• Add folder
Example of request
POST /service/soap/CreateAppointmentRequest HTTP/1.1
Content-Type: text/xml; charset=utf-8
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
	 <soap:Header>
	 	 <context xmlns="urn:zimbra"><authToken>0_b6e206e6c3eee19a7e89f717d5972d9d6b9db224</authToken>...</context>
	 </soap:Header>
	 <soap:Body>
	 	 <CreateAppointmentRequest xmlns="urn:zimbraMail">
	 	 	 <m l="10">
	 	 	 	 <inv>
	 	 	 	 	 <comp status="CONF" allDay="0" name="Titre de la rencontre" loc="Montr[0xc3][0xa9]al" class="PUB" transp="O" fb="B">
	 	 	 	 	 	 <s d="20130619T050858" tz="America/Montreal"/>
	 	 	 	 	 	 <e d="20130619T070858" tz="America/Montreal"/>
	 	 	 	 	 	 <or d="Pascal Robert" a="root@zimbra.macti.lan"/>
	 	 	 	 	 	 <at d="Pascal Robert" cutype="IND" a="probert@macti.ca"/>
	 	 	 	 	 	 <at d="Salle 1" cutype="ROO" a="Room1@zimbra.macti.lan"/>
	 	 	 	 	 	 <xprop name="X-RELATED-TO" value="281-280"/>
	 	 	 	 	 </comp>
	 	 	 	 </inv>
	 	 	 	 <su>Titre de la rencontre</su>
	 	 	 	 <mp ct="multipart/mixed"><mp ct="text/plain">
	 	 	 	 	 <content>Une plus long description</content>
	 	 	 	 </mp>
	 	 	 	 <mp ct="text/html">
	 	 	 	 	 <content>&lt;html>&lt;body> Une plus long description&lt;/body>&lt;/html></content>
	 	 	 	 </mp>
	 	 	 </m>
	 	 </CreateAppointmentRequest>
	 </soap:Body>
</soap:Envelope>
Example response
HTTP/1.1 200 OK
Content-Type: text/xml;charset=UTF-8
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
	 <soap:Header>
	 	 <context xmlns="urn:zimbra"><session id="11">11</session><change token="602"/>
	 	 	 <notify seq="2">
	 	 	 	 <created>
	 	 	 	 	 <appt id="283" uid="4ec78d56-0061-451d-9825-cb17b43b010b" d="1371632938000" rev="602" s="0" l="10">
	 	 	 	 	 	 <inv id="282" seq="0" compNum="0" type="appt">
	 	 	 	 	 	 	 <tz id="America/Montreal" stdoff="-300" dayname="EDT" dayoff="-240" stdname="EST">...</tz>
	 	 	 	 	 	 	 <comp uid="4ec78d56-0061-451d-9825-cb17b43b010b" d="1371632938000" status="CONF" ...>
	 	 	 	 	 	 	 	 <at d="Pascal Robert" cutype="IND" a="probert@macti.ca" url="probert@macti.ca"/>
	 	 	 	 	 	 	 	 <at d="Salle 1" cutype="ROO" a="Room1@zimbra.macti.lan" url="Room1@zimbra.macti.lan"/>
	 	 	 	 	 	 	 	 <xprop name="X-RELATED-TO" value="281-280"/>
	 	 	 	 	 	 	 	 <desc>Une plus long description</desc>
	 	 	 	 	 	 	 	 <descHtml>&lt;html>&lt;body> Une plus long description&lt;/body>&lt;/html></descHtml>
	 	 	 	 	 	 	 	 <or d="Pascal Robert" a="admin@linux.conatus.lan" url="root@zimbra.macti.lan"/>
	 	 	 	 	 	 	 	 <s u="1371632938000" d="20130619T050858" tz="America/Montreal"/>
	 	 	 	 	 	 	 	 <e d="20130619T070858" u="1371640138000" tz="America/Montreal"/>
	 	 	 	 	 	 	 </comp>
	 	 	 	 	 	 </inv>
	 	 	 	 	 </appt>
	 	 	 	 </created>
	 	 	 	 <modified><folder id="10" i4next="284" s="0" i4ms="602" n="3" uuid="6630b004-40cd-49b4-af4b-eca7bac45be6"/></modified>
	 	 	 </notify>
	 	 </context>
	 </soap:Header>
	 <soap:Body>
	 	 <CreateAppointmentResponse rev="602" ms="602" invId="283-282" apptId="283" calItemId="283" xmlns="urn:zimbraMail"/>
	 </soap:Body>
</soap:Envelope>
TODO
• Move away from ical4j-connector
• Complete CalDAV and CardDAV support
• Complete calendar, contacts and email support for Zimbra
• Management API for Kerio, CGP and Zimbra
Resources
• https://github.com/pascalrobert/ERGroupware/
• http://www.macti.ca/wiki/
• http://www.calconnect.org
• http://wiki.modularity.net.au/ical4j/
• http://msdn.microsoft.com/en-us/library/exchange/bb204119(v=exchg.
140).aspx
Q&A

More Related Content

What's hot

20141002 delapsley-socalangularjs-final
20141002 delapsley-socalangularjs-final20141002 delapsley-socalangularjs-final
20141002 delapsley-socalangularjs-finalDavid Lapsley
 
20140821 delapsley-cloudopen-public
20140821 delapsley-cloudopen-public20140821 delapsley-cloudopen-public
20140821 delapsley-cloudopen-publicDavid Lapsley
 
Omnisearch in AEM 6.2 - Search All the Things
Omnisearch in AEM 6.2 - Search All the ThingsOmnisearch in AEM 6.2 - Search All the Things
Omnisearch in AEM 6.2 - Search All the ThingsJustin Edelson
 
Javascript Application Architecture with Backbone.JS
Javascript Application Architecture with Backbone.JSJavascript Application Architecture with Backbone.JS
Javascript Application Architecture with Backbone.JSMin Ming Lo
 
Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Matthew Groves
 
Demystifying Oak Search
Demystifying Oak SearchDemystifying Oak Search
Demystifying Oak SearchJustin Edelson
 
Effiziente Datenpersistierung mit JPA 2.1 und Hibernate
Effiziente Datenpersistierung mit JPA 2.1 und HibernateEffiziente Datenpersistierung mit JPA 2.1 und Hibernate
Effiziente Datenpersistierung mit JPA 2.1 und HibernateThorben Janssen
 
Barcamp Auckland Rails3 presentation
Barcamp Auckland Rails3 presentationBarcamp Auckland Rails3 presentation
Barcamp Auckland Rails3 presentationSociable
 
Adventures in Multithreaded Core Data
Adventures in Multithreaded Core DataAdventures in Multithreaded Core Data
Adventures in Multithreaded Core DataInferis
 
Create a Core Data Observer in 10mins
Create a Core Data Observer in 10minsCreate a Core Data Observer in 10mins
Create a Core Data Observer in 10minszmcartor
 
Using redux and angular 2 with meteor
Using redux and angular 2 with meteorUsing redux and angular 2 with meteor
Using redux and angular 2 with meteorKen Ono
 
Memory Management on iOS
Memory Management on iOSMemory Management on iOS
Memory Management on iOSMake School
 
Akka Actor presentation
Akka Actor presentationAkka Actor presentation
Akka Actor presentationGene Chang
 
Riak with node.js
Riak with node.jsRiak with node.js
Riak with node.jsSean Cribbs
 
iOS Memory Management Basics
iOS Memory Management BasicsiOS Memory Management Basics
iOS Memory Management BasicsBilue
 
Memory management in Objective C
Memory management in Objective CMemory management in Objective C
Memory management in Objective CNeha Gupta
 

What's hot (18)

20141002 delapsley-socalangularjs-final
20141002 delapsley-socalangularjs-final20141002 delapsley-socalangularjs-final
20141002 delapsley-socalangularjs-final
 
20140821 delapsley-cloudopen-public
20140821 delapsley-cloudopen-public20140821 delapsley-cloudopen-public
20140821 delapsley-cloudopen-public
 
Omnisearch in AEM 6.2 - Search All the Things
Omnisearch in AEM 6.2 - Search All the ThingsOmnisearch in AEM 6.2 - Search All the Things
Omnisearch in AEM 6.2 - Search All the Things
 
Javascript Application Architecture with Backbone.JS
Javascript Application Architecture with Backbone.JSJavascript Application Architecture with Backbone.JS
Javascript Application Architecture with Backbone.JS
 
Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017Full stack development with node and NoSQL - All Things Open - October 2017
Full stack development with node and NoSQL - All Things Open - October 2017
 
Demystifying Oak Search
Demystifying Oak SearchDemystifying Oak Search
Demystifying Oak Search
 
Effiziente Datenpersistierung mit JPA 2.1 und Hibernate
Effiziente Datenpersistierung mit JPA 2.1 und HibernateEffiziente Datenpersistierung mit JPA 2.1 und Hibernate
Effiziente Datenpersistierung mit JPA 2.1 und Hibernate
 
Oak Lucene Indexes
Oak Lucene IndexesOak Lucene Indexes
Oak Lucene Indexes
 
Barcamp Auckland Rails3 presentation
Barcamp Auckland Rails3 presentationBarcamp Auckland Rails3 presentation
Barcamp Auckland Rails3 presentation
 
Adventures in Multithreaded Core Data
Adventures in Multithreaded Core DataAdventures in Multithreaded Core Data
Adventures in Multithreaded Core Data
 
CDI 2.0 Deep Dive
CDI 2.0 Deep DiveCDI 2.0 Deep Dive
CDI 2.0 Deep Dive
 
Create a Core Data Observer in 10mins
Create a Core Data Observer in 10minsCreate a Core Data Observer in 10mins
Create a Core Data Observer in 10mins
 
Using redux and angular 2 with meteor
Using redux and angular 2 with meteorUsing redux and angular 2 with meteor
Using redux and angular 2 with meteor
 
Memory Management on iOS
Memory Management on iOSMemory Management on iOS
Memory Management on iOS
 
Akka Actor presentation
Akka Actor presentationAkka Actor presentation
Akka Actor presentation
 
Riak with node.js
Riak with node.jsRiak with node.js
Riak with node.js
 
iOS Memory Management Basics
iOS Memory Management BasicsiOS Memory Management Basics
iOS Memory Management Basics
 
Memory management in Objective C
Memory management in Objective CMemory management in Objective C
Memory management in Objective C
 

Similar to ERGroupware

Integrating Bedework, a CalDAV Calendar Server, into OAE
Integrating Bedework, a CalDAV Calendar Server, into OAEIntegrating Bedework, a CalDAV Calendar Server, into OAE
Integrating Bedework, a CalDAV Calendar Server, into OAEctweney
 
Apache cassandra & apache spark for time series data
Apache cassandra & apache spark for time series dataApache cassandra & apache spark for time series data
Apache cassandra & apache spark for time series dataPatrick McFadin
 
Real time Analytics with Apache Kafka and Apache Spark
Real time Analytics with Apache Kafka and Apache SparkReal time Analytics with Apache Kafka and Apache Spark
Real time Analytics with Apache Kafka and Apache SparkRahul Jain
 
Scala for scripting
Scala for scriptingScala for scripting
Scala for scriptingmichid
 
ApacheCon NA 2015 Spark / Solr Integration
ApacheCon NA 2015 Spark / Solr IntegrationApacheCon NA 2015 Spark / Solr Integration
ApacheCon NA 2015 Spark / Solr Integrationthelabdude
 
Scala for scripting
Scala for scriptingScala for scripting
Scala for scriptingday
 
Pro2516 10 things about oracle and k8s.pptx-final
Pro2516   10 things about oracle and k8s.pptx-finalPro2516   10 things about oracle and k8s.pptx-final
Pro2516 10 things about oracle and k8s.pptx-finalMichel Schildmeijer
 
The Developer Conference - CloudKit, entendendo a Cloud da Apple
The Developer Conference - CloudKit, entendendo a Cloud da AppleThe Developer Conference - CloudKit, entendendo a Cloud da Apple
The Developer Conference - CloudKit, entendendo a Cloud da AppleRodrigo Leite
 
Architecting Alive Apps
Architecting Alive AppsArchitecting Alive Apps
Architecting Alive AppsJorge Ortiz
 
DataSource V2 and Cassandra – A Whole New World
DataSource V2 and Cassandra – A Whole New WorldDataSource V2 and Cassandra – A Whole New World
DataSource V2 and Cassandra – A Whole New WorldDatabricks
 
Staying Ahead of the Curve with Spring and Cassandra 4
Staying Ahead of the Curve with Spring and Cassandra 4Staying Ahead of the Curve with Spring and Cassandra 4
Staying Ahead of the Curve with Spring and Cassandra 4VMware Tanzu
 
Staying Ahead of the Curve with Spring and Cassandra 4 (SpringOne 2020)
Staying Ahead of the Curve with Spring and Cassandra 4 (SpringOne 2020)Staying Ahead of the Curve with Spring and Cassandra 4 (SpringOne 2020)
Staying Ahead of the Curve with Spring and Cassandra 4 (SpringOne 2020)Alexandre Dutra
 
Continuous Deployment with Akka.Cluster and Kubernetes (Akka.NET)
Continuous Deployment with Akka.Cluster and Kubernetes (Akka.NET)Continuous Deployment with Akka.Cluster and Kubernetes (Akka.NET)
Continuous Deployment with Akka.Cluster and Kubernetes (Akka.NET)petabridge
 
Event Sourcing - what could go wrong - Jfokus 2022
Event Sourcing - what could go wrong - Jfokus 2022Event Sourcing - what could go wrong - Jfokus 2022
Event Sourcing - what could go wrong - Jfokus 2022Andrzej Ludwikowski
 
SQL on Hadoop
SQL on HadoopSQL on Hadoop
SQL on Hadoopnvvrajesh
 
Cassandra Java APIs Old and New – A Comparison
Cassandra Java APIs Old and New – A ComparisonCassandra Java APIs Old and New – A Comparison
Cassandra Java APIs Old and New – A Comparisonshsedghi
 
StackWatch: A prototype CloudWatch service for CloudStack
StackWatch: A prototype CloudWatch service for CloudStackStackWatch: A prototype CloudWatch service for CloudStack
StackWatch: A prototype CloudWatch service for CloudStackChiradeep Vittal
 
Managing Your Content with Elasticsearch
Managing Your Content with ElasticsearchManaging Your Content with Elasticsearch
Managing Your Content with ElasticsearchSamantha Quiñones
 

Similar to ERGroupware (20)

Integrating Bedework, a CalDAV Calendar Server, into OAE
Integrating Bedework, a CalDAV Calendar Server, into OAEIntegrating Bedework, a CalDAV Calendar Server, into OAE
Integrating Bedework, a CalDAV Calendar Server, into OAE
 
Apache cassandra & apache spark for time series data
Apache cassandra & apache spark for time series dataApache cassandra & apache spark for time series data
Apache cassandra & apache spark for time series data
 
Real time Analytics with Apache Kafka and Apache Spark
Real time Analytics with Apache Kafka and Apache SparkReal time Analytics with Apache Kafka and Apache Spark
Real time Analytics with Apache Kafka and Apache Spark
 
Scala for scripting
Scala for scriptingScala for scripting
Scala for scripting
 
ApacheCon NA 2015 Spark / Solr Integration
ApacheCon NA 2015 Spark / Solr IntegrationApacheCon NA 2015 Spark / Solr Integration
ApacheCon NA 2015 Spark / Solr Integration
 
Scala for scripting
Scala for scriptingScala for scripting
Scala for scripting
 
Pro2516 10 things about oracle and k8s.pptx-final
Pro2516   10 things about oracle and k8s.pptx-finalPro2516   10 things about oracle and k8s.pptx-final
Pro2516 10 things about oracle and k8s.pptx-final
 
Spark etl
Spark etlSpark etl
Spark etl
 
The Developer Conference - CloudKit, entendendo a Cloud da Apple
The Developer Conference - CloudKit, entendendo a Cloud da AppleThe Developer Conference - CloudKit, entendendo a Cloud da Apple
The Developer Conference - CloudKit, entendendo a Cloud da Apple
 
Architecting Alive Apps
Architecting Alive AppsArchitecting Alive Apps
Architecting Alive Apps
 
DataSource V2 and Cassandra – A Whole New World
DataSource V2 and Cassandra – A Whole New WorldDataSource V2 and Cassandra – A Whole New World
DataSource V2 and Cassandra – A Whole New World
 
Unqlite
UnqliteUnqlite
Unqlite
 
Staying Ahead of the Curve with Spring and Cassandra 4
Staying Ahead of the Curve with Spring and Cassandra 4Staying Ahead of the Curve with Spring and Cassandra 4
Staying Ahead of the Curve with Spring and Cassandra 4
 
Staying Ahead of the Curve with Spring and Cassandra 4 (SpringOne 2020)
Staying Ahead of the Curve with Spring and Cassandra 4 (SpringOne 2020)Staying Ahead of the Curve with Spring and Cassandra 4 (SpringOne 2020)
Staying Ahead of the Curve with Spring and Cassandra 4 (SpringOne 2020)
 
Continuous Deployment with Akka.Cluster and Kubernetes (Akka.NET)
Continuous Deployment with Akka.Cluster and Kubernetes (Akka.NET)Continuous Deployment with Akka.Cluster and Kubernetes (Akka.NET)
Continuous Deployment with Akka.Cluster and Kubernetes (Akka.NET)
 
Event Sourcing - what could go wrong - Jfokus 2022
Event Sourcing - what could go wrong - Jfokus 2022Event Sourcing - what could go wrong - Jfokus 2022
Event Sourcing - what could go wrong - Jfokus 2022
 
SQL on Hadoop
SQL on HadoopSQL on Hadoop
SQL on Hadoop
 
Cassandra Java APIs Old and New – A Comparison
Cassandra Java APIs Old and New – A ComparisonCassandra Java APIs Old and New – A Comparison
Cassandra Java APIs Old and New – A Comparison
 
StackWatch: A prototype CloudWatch service for CloudStack
StackWatch: A prototype CloudWatch service for CloudStackStackWatch: A prototype CloudWatch service for CloudStack
StackWatch: A prototype CloudWatch service for CloudStack
 
Managing Your Content with Elasticsearch
Managing Your Content with ElasticsearchManaging Your Content with Elasticsearch
Managing Your Content with Elasticsearch
 

More from WO Community

In memory OLAP engine
In memory OLAP engineIn memory OLAP engine
In memory OLAP engineWO Community
 
Using Nagios to monitor your WO systems
Using Nagios to monitor your WO systemsUsing Nagios to monitor your WO systems
Using Nagios to monitor your WO systemsWO Community
 
Build and deployment
Build and deploymentBuild and deployment
Build and deploymentWO Community
 
Reenabling SOAP using ERJaxWS
Reenabling SOAP using ERJaxWSReenabling SOAP using ERJaxWS
Reenabling SOAP using ERJaxWSWO Community
 
Chaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real WorldChaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real WorldWO Community
 
D2W Stateful Controllers
D2W Stateful ControllersD2W Stateful Controllers
D2W Stateful ControllersWO Community
 
Deploying WO on Windows
Deploying WO on WindowsDeploying WO on Windows
Deploying WO on WindowsWO Community
 
Unit Testing with WOUnit
Unit Testing with WOUnitUnit Testing with WOUnit
Unit Testing with WOUnitWO Community
 
Apache Cayenne for WO Devs
Apache Cayenne for WO DevsApache Cayenne for WO Devs
Apache Cayenne for WO DevsWO Community
 
Advanced Apache Cayenne
Advanced Apache CayenneAdvanced Apache Cayenne
Advanced Apache CayenneWO Community
 
Migrating existing Projects to Wonder
Migrating existing Projects to WonderMigrating existing Projects to Wonder
Migrating existing Projects to WonderWO Community
 
"Framework Principal" pattern
"Framework Principal" pattern"Framework Principal" pattern
"Framework Principal" patternWO Community
 
Filtering data with D2W
Filtering data with D2W Filtering data with D2W
Filtering data with D2W WO Community
 
Localizing your apps for multibyte languages
Localizing your apps for multibyte languagesLocalizing your apps for multibyte languages
Localizing your apps for multibyte languagesWO Community
 

More from WO Community (20)

KAAccessControl
KAAccessControlKAAccessControl
KAAccessControl
 
In memory OLAP engine
In memory OLAP engineIn memory OLAP engine
In memory OLAP engine
 
Using Nagios to monitor your WO systems
Using Nagios to monitor your WO systemsUsing Nagios to monitor your WO systems
Using Nagios to monitor your WO systems
 
Build and deployment
Build and deploymentBuild and deployment
Build and deployment
 
High availability
High availabilityHigh availability
High availability
 
Reenabling SOAP using ERJaxWS
Reenabling SOAP using ERJaxWSReenabling SOAP using ERJaxWS
Reenabling SOAP using ERJaxWS
 
Chaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real WorldChaining the Beast - Testing Wonder Applications in the Real World
Chaining the Beast - Testing Wonder Applications in the Real World
 
D2W Stateful Controllers
D2W Stateful ControllersD2W Stateful Controllers
D2W Stateful Controllers
 
Deploying WO on Windows
Deploying WO on WindowsDeploying WO on Windows
Deploying WO on Windows
 
Unit Testing with WOUnit
Unit Testing with WOUnitUnit Testing with WOUnit
Unit Testing with WOUnit
 
Life outside WO
Life outside WOLife outside WO
Life outside WO
 
Apache Cayenne for WO Devs
Apache Cayenne for WO DevsApache Cayenne for WO Devs
Apache Cayenne for WO Devs
 
Advanced Apache Cayenne
Advanced Apache CayenneAdvanced Apache Cayenne
Advanced Apache Cayenne
 
Migrating existing Projects to Wonder
Migrating existing Projects to WonderMigrating existing Projects to Wonder
Migrating existing Projects to Wonder
 
iOS for ERREST
iOS for ERRESTiOS for ERREST
iOS for ERREST
 
"Framework Principal" pattern
"Framework Principal" pattern"Framework Principal" pattern
"Framework Principal" pattern
 
Filtering data with D2W
Filtering data with D2W Filtering data with D2W
Filtering data with D2W
 
WOver
WOverWOver
WOver
 
Localizing your apps for multibyte languages
Localizing your apps for multibyte languagesLocalizing your apps for multibyte languages
Localizing your apps for multibyte languages
 
WOdka
WOdkaWOdka
WOdka
 

Recently uploaded

Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?XfilesPro
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your Budget
Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your BudgetHyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your Budget
Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your BudgetEnjoy Anytime
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxnull - The Open Security Community
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 

Recently uploaded (20)

Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptxVulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your Budget
Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your BudgetHyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your Budget
Hyderabad Call Girls Khairatabad ✨ 7001305949 ✨ Cheap Price Your Budget
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 

ERGroupware

  • 2. • Let you generate iCalendar files, à la ERCalendar • Let you connect to groupware solutions • CalDAV • MS Exchange 2007/2010 • Zimbra • Many Bothans have died to provide this framework What is ERGroupware?
  • 4. iCalendar • iCalendar is a standard (RFC 2445, written in 1998). • A iCalendar object can have multiple components (VEVENT, VTODO, etc.) • Text file, with Base64 encoding for binary • Key value • You can add your own keys
  • 5. iCalendar example BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Apple Inc.//Mac OS X 10.8.4//EN CALSCALE:GREGORIAN BEGIN:VEVENT TRANSP:OPAQUE DTEND:20130623T101500 UID:DB0E22EA-0828-40A3-BCFD-5A8CC9866CE4 DTSTAMP:20130514T135551Z LOCATION:Verdun/Lachine/Lasalle X-MOZ-GENERATION:1 URL;VALUE=URI:http://www.wocommunity.org/wowodc13/cayenne.html SEQUENCE:10 SUMMARY:Cayenne Training Day LAST-MODIFIED:20130509T165550Z DTSTART:20130623T091500 CREATED:20130505T001152Z END:VEVENT END:VCALENDAR
  • 6. UID • Each component must have a UID • UID:DB0E22EA-0828-40A3-BCFD-5A8CC9866CE4 • And it must be unique!
  • 7. Attendees • Attendees are invitees. • Can be a individual, group, resource or room. (CUType) • Also have status: needs action, accepted, etc. (Partstat) • If you have attendees, you also need an organizer!
  • 8. iCalendar in ERGroupware • Similar to ERCalendar, but more modern and better validation. • Using iCal4j, a solid iCalendar library for Java. • Component to generate the file. • Will generate a text/calendar response
  • 9. iCalendar file generation ERGWCalendar aCalendar = new ERGWCalendar(); ERGWEvent event = new ERGWEvent(aCalendar); java.util.Calendar startTime = GregorianCalendar.getInstance(); event.setStartTime(new NSTimestamp(startTime.getTimeInMillis())); java.util.Calendar endTime = GregorianCalendar.getInstance(); endTime.add(java.util.Calendar.HOUR, 2); event.setEndTime(new NSTimestamp(endTime.getTimeInMillis())); event.setClassification(ERGWClassification.PUBLIC); event.setFreeBusyStatus(ERGWFreeBusyStatus.BUSY_TENTATIVE); event.setLocation("Montreal"); event.setCategories(new NSArray<String>(new String[] { "Category 1", "Category 2" })); event.setPriority(ERGWPriority.HIGH); event.setSummary("WOWODC 2013"); event.setTransparency(ERGWTransparency.TRANSPARENT); Calendar calendarData = ERGWCalendar.transformToICalObject(aCalendar); ERGWPublishCalendarPage nextPage = (ERGWPublishCalendarPage)pageWithName(ERGWPublishCalendarPage.class); nextPage.setCalendar(calendarData); return nextPage;
  • 10. CalDAV/CardDAV • Both based on WebDAV • Will store iCalendar objects (CalDAV) or vCard objects (CardDAV) • Many many server implementations • But some of them are really basic (Google Calendar...) • iCal Server is the best implementation • Many clients too
  • 11. CalDAV • Open standard, defined in RFC 4791 • Servers must implements this RFC • Many extensions • Scheduling • Delegations • Sharing • etc.
  • 12. CalDAV • Calendars are DAV collections. • DAV collections have properties (ACL, owner, etc.). • Can create as many collections as you want. • Other DAV collections exists too.
  • 13. Features/extensions • CalDAV servers must send the supported features set in the response. • Can do a OPTIONS request to see them. • Check the DAV header in the response.
  • 14. OPTIONS request $ curl --digest --user probert -X OPTIONS -v http://localhost:8008 < DAV: 1, access-control, calendar-access, calendar-schedule, calendar- auto-schedule, calendar-availability, inbox-availability, calendar- proxy, calendarserver-private-events, calendarserver-private-comments, calendarserver-sharing, calendarserver-sharing-no-scheduling, calendar- query-extended, calendar-default-alarms, addressbook, extended-mkcol, calendarserver-principal-property-search, calendarserver-principal- search
  • 15. CalDAV and HTTP • Almost REST-like • Use HTTP verbs • GET: fetch a object • PUT: create OR update a object • DELETE: delete a object • MKCALENDAR: create a calendar collection • Use headers, HTTP authentication (Basic, Digest, Kerberos...)
  • 16. iCalendar objects • You store iCalendar objects in calendar collections. • But you can only store ONE component (VTODO,VEVENT, etc.) per object.
  • 17. PUT • CalDAV don't use POST to create objects. • Must use PUT • If URL and UID already exists, will update the object. • If URL and UID don't exists, will create the object. • If URL don't exist but UID exist, will conflict. • Creating a object will return a 201 status code. • If you copy an object, don't forget to change the UID.
  • 18. Example of creating event PUT /calendars/__uids__/AD04C60B-3704-447B-8997-24F5ACF589C7/calendar/C440-473C-8FAD-D3E606159F40.ics HTTP/1.1 If-None-Match: 1f9e6e30-dfdb-4e5c-baf6-6dd107126a68 Content-Type: text/calendar BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Apple Inc.//Mac OS X 10.8.4//EN CALSCALE:GREGORIAN BEGIN:VEVENT ATTENDEE;CN="probert@macti.ca";CUTYPE=INDIVIDUAL:mailto:probert@macti.ca ATTENDEE;CN="Pascal Robert";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:urn:uuid:AD04C60B-3704-447B-8997-24F5ACF589C7 DTEND;VALUE=DATE:20130616 TRANSP:TRANSPARENT ORGANIZER;CN="Pascal Robert":urn:uuid:AD04C60B-3704-447B-8997-24F5ACF589C7 UID:B54100D2-C440-473C-8FAD-D3E606159F40 DTSTAMP:20130615T123551Z LOCATION:Hilton Montréal Bonaventure SEQUENCE:9 SUMMARY:Test for presentation DTSTART;VALUE=DATE:20130615 CREATED:20130615T123241Z END:VEVENT END:VCALENDAR
  • 19. CalDAV support in ERGroupware • Based on iCal4j-connector, which I contributed to. • Support for most CalDAV operations. • Get calendars (collections) • Create calendars • Fetch/delete/update calendar objects • Delete collections • Fetch events by time-range
  • 20. Connecting import net.fortuna.ical4j.connector.ObjectStoreException; import net.fortuna.ical4j.connector.dav.PathResolver; import er.groupware.caldav.CalDAVStore; import java.net.URL; CalDAVStore store = null; try { store = new CalDAVStore("probert", "somepassword", new URL("http://127.0.0.1"), PathResolver.ICAL_SERVER); } catch (MalformedURLException e) { e.printStackTrace(); } catch (ObjectStoreException e) { e.printStackTrace(); }
  • 21. Fetching calendar collections and objects NSArray<CalDAVCollection> collections = store.getCollections(); for (CalDAVCollection collection: collections) { NSLog.out.appendln(collection.displayName()); // Fetch all events (e.g, VEVENT objects) NSArray<ERGWCalendar> events = collection.events(); // Fetch all tasks (e.g, VTOTO objects) NSArray<ERGWCalendar> tasks = collection.tasks(); }
  • 22. Manipuling calendar objects // Create a new event and send it to the server ERGWCalendar aCalendar = new ERGWCalendar(); ERGWEvent event = new ERGWEvent(aCalendar); java.util.Calendar startTime = GregorianCalendar.getInstance(); event.setStartTime(new NSTimestamp(startTime.getTimeInMillis())); java.util.Calendar endTime = GregorianCalendar.getInstance(); endTime.add(java.util.Calendar.HOUR, 2); event.setEndTime(new NSTimestamp(endTime.getTimeInMillis())); event.setSummary("WOWODC 2013"); collection.addCalendarObject(aCalendar); // Update the event and send it to the server aCalendar.events().objectAtIndex(0).setSummary("WOWODC 2014"); collection.updateCalendarObject(aCalendar); // Delete the event collection.removeCalendarObject(aCalendar.events().objectAtIndex(0));
  • 23. Queries • REPORT request is the same idea as a SQL SELECT query. • Let's you find calendar objects with a qualifier. • "Find all todos that are completed" • "Find events from June 22 to June 24" • "Find all rooms" • Won't work for custom properties
  • 24. Find events by time range REPORT /bernard/work/ HTTP/1.1 Depth: 1 Content-Type: application/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav"> <D:prop> <C:calendar-data> <C:limit-recurrence-set start="20060103T000000Z" end="20060105T000000Z"/> </C:calendar-data> </D:prop> <C:filter> <C:comp-filter name="VCALENDAR"> <C:comp-filter name="VEVENT"> <C:time-range start="20060103T000000Z" end="20060105T000000Z"/> </C:comp-filter> </C:comp-filter> </C:filter> </C:calendar-query>
  • 25. Find participants that didn't not accept invitations REPORT /bernard/work/ HTTP/1.1 Depth: 1 Content-Type: application/xml; charset="utf-8" <?xml version="1.0" encoding="utf-8" ?> <C:calendar-query xmlns:C="urn:ietf:params:xml:ns:caldav"> <D:prop xmlns:D="DAV:"> <D:getetag/> <C:calendar-data/> </D:prop> <C:filter> <C:comp-filter name="VCALENDAR"> <C:comp-filter name="VEVENT"> <C:prop-filter name="ATTENDEE"> <C:param-filter name="PARTSTAT"> <C:text-match collation="i;ascii-casemap">NEEDS-ACTION</C:text-match> </C:param-filter> </C:prop-filter> </C:comp-filter> </C:comp-filter> </C:filter> </C:calendar-query>
  • 26. Queries support in ERGroupware • Query by time range • CalDavCollection.eventsForTimePeriod(java.util.Date startTime, java.util.Date endTime) • Find all individuals • store.getIndividuals(String name); • Find rooms or resources • store.getAllRooms() • store.getAllResources()
  • 27. DEMO
  • 28. MS Exchange • Exchange Web Service (EWS) • Based on SOAP • Same protocol that Outlook 2011 uses • Most EWS attributes are similar to iCalendar and DAV collections attributes
  • 29. Example of request ---[HTTP request - https://webmail.sherweb2010.com/EWS/Exchange.asmx]--- Content-type: text/xml;charset="utf-8" Soapaction: "http://schemas.microsoft.com/exchange/services/2006/messages/SyncFolderHierarchy" Accept: text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 <?xml version="1.0" ?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Header> <MailboxCulture xmlns="..." xmlns:ns2="...">en-US</MailboxCulture> <RequestServerVersion xmlns="..." xmlns:ns2="..." Version="Exchange2007_SP1"/> </S:Header> <S:Body> <ns2:SyncFolderHierarchy xmlns="..." xmlns:ns2="..."> <ns2:FolderShape> <BaseShape>IdOnly</BaseShape> <AdditionalProperties> <FieldURI FieldURI="folder:DisplayName"/> <FieldURI FieldURI="folder:FolderClass"/> <ExtendedFieldURI PropertyType="Boolean" PropertyTag="0x10F4"/> </AdditionalProperties> </ns2:FolderShape> </ns2:SyncFolderHierarchy> </S:Body> </S:Envelope>
  • 30. Example of response <?xml version="1.0" encoding="utf-8"?> <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Header> <h:ServerVersionInfo ... Version="Exchange2010_SP2" /> </s:Header> <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <m:SyncFolderHierarchyResponse xmlns:m="..." xmlns:t="..."><m:ResponseMessages> <m:SyncFolderHierarchyResponseMessage ResponseClass="Success"> <m:ResponseCode>NoError</m:ResponseCode> <m:SyncState>H4sIAAAAAAAEAO29B2AcSZYlJi9tynt...</m:SyncState> <m:Changes> <t:Create> <t:Folder> <t:FolderId Id="AAMkAGEw...=" ChangeKey="AQAAABYAAACT3PaCL/2ASLnqcq9Sv0/DAAAAp5Bv"/> <t:FolderClass>IPF.Note</t:FolderClass> <t:DisplayName>INBOX</t:DisplayName> <t:ExtendedProperty> <t:ExtendedFieldURI PropertyTag="0x10f4" PropertyType="Boolean"/> <t:Value>false</t:Value> </t:ExtendedProperty> </t:Folder> </t:Create> </m:Changes> ...
  • 31. EWS support in ERGroupware • Generated with JAXB. • Very basic support outside the generated classes: • Open connection • Create folders • Create task • Create contact • Create event
  • 32. Opening a connection and fetch folders URL urlToWSDL = ERXApplication.application().resourceManager().pathURLForResourceNamed("Services.wsdl", "ERGroupware", null); ExchangeStore store = new ExchangeStore(urlToWSDL, "https://myserver/EWS/Exchange.asmx", "aUser", "aPassword", "AD.DOMAIN"); store.setServerVersionForRequest(ExchangeVersionType.EXCHANGE_2010_SP_1); store.setTimeZone(TimeZone.getDefault()); NSArray<ExchangeBaseFolder> folders = store.folders(); for (ExchangeBaseFolder folder: folders) { NSLog.out.appendln(folder.displayName()); }
  • 33. Adding an event for (ExchangeBaseFolder folder: store.folders()) { if (folder.displayName().equals("Calendar")) { ERGWCalendar calendar = new ERGWCalendar(); calendar.setCalendarName("Test"); calendar.setTimeZone(TimeZone.getDefault()); Calendar later = GregorianCalendar.getInstance(); later.add(Calendar.HOUR_OF_DAY, 1); event.setEndTime(new NSTimestamp(later.getTime())); UidGenerator uidGen = new UidGenerator("allo"); event.setUid(uidGen.generateUid().getValue()); ERGWEvent event = new ERGWEvent(calendar); event.setIsFullDay(false); event.setStartTime(new NSTimestamp()); event.setSummary("WOWODC 2013"); event.setLastModifiedDate(new NSTimestamp()); calendar.addEvent(event); exchangeStore.createCalendarEvent(calendar, (ExchangeCalendarFolder) folder); } }
  • 34. Adding an event for (ExchangeBaseFolder folder: store.folders()) { if (folder.displayName().equals("Tasks")) { ERGWCalendar calendar = new ERGWCalendar(); calendar.setCalendarName("Test"); calendar.setTimeZone(TimeZone.getDefault()); Calendar later = GregorianCalendar.getInstance(); later.add(Calendar.HOUR_OF_DAY, 1); task.setDueDate(new NSTimestamp(later.getTime())); UidGenerator uidGen = new UidGenerator("allo"); event.setUid(uidGen.generateUid().getValue()); ERGWTask task = new ERGWTask(calendar); task.setSummary("Finish that presentation"); task.setLastModifiedDate(new NSTimestamp()); calendar.addEvent(event); exchangeStore.createTask(calendar, (ExchangeCalendarFolder) folder); } }
  • 35. Adding a contact for (ExchangeBaseFolder folder: store.folders()) { if (folder.displayName().equals("Contacts")) { ERGWContact contact = new ERGWContact(); contact.setGivenName("Pascal"); contact.setFamilyName("Robert"); ERGWContactEmail personalEmail = new ERGWContactEmail(); personalEmail.setEmail("probert@macti.ca"); personalEmail.isPrefered(true); personalEmail.setTypes(new NSArray<ERGWContactEmailType>(new ERGWContactEmailType[] { ERGWContactEmailType.HOME })); contact.setEmails(new NSArray<ERGWContactEmail>(new ERGWContactEmail[] { personalEmail })); exchangeStore.createContact(contact, (ExchangeCalendarFolder) folder); } }
  • 36. Create folders // Create a folder of a specific type // ERGWFolderType values are: CALENDAR, CONTACTS, TASKS, SEARCH, PLAIN, etc. store.createFolder("New calendar folder", ERGWFolderType.CALENDAR); store.createFolder("New contacts folder", ERGWFolderType.CONTACTS); // Shortcut to create a calendar folder store.createCalendarFolder(String displayName) // Shortcut to create a contacts folder store.createContactsFolder(String displayName)
  • 37. Zimbra • SOAP and REST-based API. • Have API for everything: management, data and Web client (Zimlets). • Very basic support in ERGroupware (need to migrate a lot of code) • Connect to store • Add folder
  • 38. Example of request POST /service/soap/CreateAppointmentRequest HTTP/1.1 Content-Type: text/xml; charset=utf-8 <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:Header> <context xmlns="urn:zimbra"><authToken>0_b6e206e6c3eee19a7e89f717d5972d9d6b9db224</authToken>...</context> </soap:Header> <soap:Body> <CreateAppointmentRequest xmlns="urn:zimbraMail"> <m l="10"> <inv> <comp status="CONF" allDay="0" name="Titre de la rencontre" loc="Montr[0xc3][0xa9]al" class="PUB" transp="O" fb="B"> <s d="20130619T050858" tz="America/Montreal"/> <e d="20130619T070858" tz="America/Montreal"/> <or d="Pascal Robert" a="root@zimbra.macti.lan"/> <at d="Pascal Robert" cutype="IND" a="probert@macti.ca"/> <at d="Salle 1" cutype="ROO" a="Room1@zimbra.macti.lan"/> <xprop name="X-RELATED-TO" value="281-280"/> </comp> </inv> <su>Titre de la rencontre</su> <mp ct="multipart/mixed"><mp ct="text/plain"> <content>Une plus long description</content> </mp> <mp ct="text/html"> <content>&lt;html>&lt;body> Une plus long description&lt;/body>&lt;/html></content> </mp> </m> </CreateAppointmentRequest> </soap:Body> </soap:Envelope>
  • 39. Example response HTTP/1.1 200 OK Content-Type: text/xml;charset=UTF-8 <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:Header> <context xmlns="urn:zimbra"><session id="11">11</session><change token="602"/> <notify seq="2"> <created> <appt id="283" uid="4ec78d56-0061-451d-9825-cb17b43b010b" d="1371632938000" rev="602" s="0" l="10"> <inv id="282" seq="0" compNum="0" type="appt"> <tz id="America/Montreal" stdoff="-300" dayname="EDT" dayoff="-240" stdname="EST">...</tz> <comp uid="4ec78d56-0061-451d-9825-cb17b43b010b" d="1371632938000" status="CONF" ...> <at d="Pascal Robert" cutype="IND" a="probert@macti.ca" url="probert@macti.ca"/> <at d="Salle 1" cutype="ROO" a="Room1@zimbra.macti.lan" url="Room1@zimbra.macti.lan"/> <xprop name="X-RELATED-TO" value="281-280"/> <desc>Une plus long description</desc> <descHtml>&lt;html>&lt;body> Une plus long description&lt;/body>&lt;/html></descHtml> <or d="Pascal Robert" a="admin@linux.conatus.lan" url="root@zimbra.macti.lan"/> <s u="1371632938000" d="20130619T050858" tz="America/Montreal"/> <e d="20130619T070858" u="1371640138000" tz="America/Montreal"/> </comp> </inv> </appt> </created> <modified><folder id="10" i4next="284" s="0" i4ms="602" n="3" uuid="6630b004-40cd-49b4-af4b-eca7bac45be6"/></modified> </notify> </context> </soap:Header> <soap:Body> <CreateAppointmentResponse rev="602" ms="602" invId="283-282" apptId="283" calItemId="283" xmlns="urn:zimbraMail"/> </soap:Body> </soap:Envelope>
  • 40. TODO • Move away from ical4j-connector • Complete CalDAV and CardDAV support • Complete calendar, contacts and email support for Zimbra • Management API for Kerio, CGP and Zimbra
  • 41. Resources • https://github.com/pascalrobert/ERGroupware/ • http://www.macti.ca/wiki/ • http://www.calconnect.org • http://wiki.modularity.net.au/ical4j/ • http://msdn.microsoft.com/en-us/library/exchange/bb204119(v=exchg. 140).aspx
  • 42. Q&A