changeset 5:8953d6ef1f06

Add initial database abstraction.
author Mario Torre <neugens.limasoftware@gmail.com>
date Thu, 07 Feb 2013 18:33:33 +0100
parents 80dd4b9b42e2
children 5e281961d0e3
files agent/pom.xml agent/src/main/resources/com/redhat/thermostat/tutorial/schedule/client/common/load.png agent/src/main/resources/com/redhat/thermostat/tutorial/schedule/client/common/locale/strings.properties agent/src/main/resources/com/redhat/thermostat/tutorial/schedule/client/common/presentation.png client-common/src/main/java/com/redhat/thermostat/tutorial/schedule/client/common/ClockView.java client-common/src/main/java/com/redhat/thermostat/tutorial/schedule/client/common/PresentationInfo.java client-controllers/.classpath client-controllers/.settings/org.eclipse.core.resources.prefs client-controllers/pom.xml client-controllers/src/main/java/com/redhat/thermostat/tutorial/schedule/client/controller/impl/ClockController.java client-controllers/src/main/java/com/redhat/thermostat/tutorial/schedule/client/controller/impl/ICalParser.java client-controllers/src/main/java/com/redhat/thermostat/tutorial/schedule/client/controller/impl/SchedulerInformationService.java client-controllers/src/main/java/com/redhat/thermostat/tutorial/schedule/client/controller/impl/SchedulerMainController.java client-controllers/src/main/java/com/redhat/thermostat/tutorial/schedule/client/controller/osgi/Activator.java client-swing/.classpath client-swing/.settings/org.eclipse.core.resources.prefs client-swing/src/main/java/com/redhat/thermostat/tutorial/schedule/client/swing/impl/ContentPanel.java client-swing/src/main/java/com/redhat/thermostat/tutorial/schedule/client/swing/impl/SwingClockView.java client-swing/src/main/java/com/redhat/thermostat/tutorial/schedule/client/swing/impl/scheduler/CurrentPresentationPanel.java client-swing/src/main/java/com/redhat/thermostat/tutorial/schedule/client/swing/impl/scheduler/PresentationInfoPanel.java copy_jars.sh plugin.conf pom.xml storage-common/pom.xml storage-common/src/main/java/com/redhat/thermostat/tutorial/schedule/storage/SchedulerDAO.java storage-common/src/main/java/com/redhat/thermostat/tutorial/schedule/storage/impl/Schedule.java storage-common/src/main/java/com/redhat/thermostat/tutorial/schedule/storage/osgi/Activator.java storage-common/src/main/resources/com/redhat/thermostat/tutorial/schedule/client/common/load.png storage-common/src/main/resources/com/redhat/thermostat/tutorial/schedule/client/common/locale/strings.properties storage-common/src/main/resources/com/redhat/thermostat/tutorial/schedule/client/common/presentation.png
diffstat 30 files changed, 957 insertions(+), 100 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/pom.xml	Thu Feb 07 18:33:33 2013 +0100
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+
+ Copyright 2012, 2013 Red Hat, Inc.
+
+ This file is part of Thermostat.
+
+ Thermostat is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ Thermostat is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Thermostat; see the file COPYING.  If not see
+ <http://www.gnu.org/licenses />.
+
+ Linking this code with other modules is making a combined work
+ based on this code.  Thus, the terms and conditions of the GNU
+ General Public License cover the whole combination.
+
+ As a special exception, the copyright holders of this code give
+ you permission to link this code with independent modules to
+ produce an executable, regardless of the license terms of these
+ independent modules, and to copy and distribute the resulting
+ executable under terms of your choice, provided that you also
+ meet, for each linked independent module, the terms and conditions
+ of the license of that module.  An independent module is a module
+ which is not derived from or based on this code.  If you modify
+ this code, you may extend this exception to your version of the
+ library, but you are not obligated to do so.  If you do not wish
+ to do so, delete this exception statement from your version.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.redhat.thermostat.tutorial.schedule</groupId>
+    <artifactId>thermostat-tutorial</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>thermostat-tutorial-agent</artifactId>
+  <packaging>bundle</packaging>
+
+  <name>Thermostat Schedule Agent</name>
+
+  <dependencies>
+      
+      <!-- osgi and test dependencies -->
+      
+      <dependency>
+          <groupId>junit</groupId>
+          <artifactId>junit</artifactId>
+          <scope>test</scope>
+      </dependency>
+    
+      <dependency>
+          <groupId>org.mockito</groupId>
+          <artifactId>mockito-core</artifactId>
+          <scope>test</scope>
+      </dependency>
+        
+      <dependency>
+          <groupId>org.osgi</groupId>
+          <artifactId>org.osgi.core</artifactId>
+          <scope>provided</scope>
+      </dependency>
+    
+      <dependency>
+          <groupId>org.osgi</groupId>
+          <artifactId>org.osgi.compendium</artifactId>
+          <scope>provided</scope>
+      </dependency>
+
+      <!-- thermostat specific dependencies -->
+    
+      <dependency>
+          <groupId>com.redhat.thermostat</groupId>
+          <artifactId>thermostat-client-core</artifactId>
+          <type>jar</type>
+      </dependency>
+      
+      <dependency>
+          <groupId>com.redhat.thermostat</groupId>
+          <artifactId>thermostat-common-core</artifactId>
+          <type>jar</type>
+      </dependency>
+    
+      <!-- plugin specific dependencies -->
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-SymbolicName>com.redhat.thermostat.tutorial.schedule.client.common</Bundle-SymbolicName>
+            <Export-Package>
+                com.redhat.thermostat.tutorial.schedule.client.common,
+                com.redhat.thermostat.tutorial.schedule.client.common.locale,
+                com.redhat.thermostat.tutorial.schedule.client.common.clock,
+            </Export-Package>
+            <!-- Do not autogenerate uses clauses in Manifests -->
+            <_nouses>true</_nouses>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
Binary file agent/src/main/resources/com/redhat/thermostat/tutorial/schedule/client/common/load.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/main/resources/com/redhat/thermostat/tutorial/schedule/client/common/locale/strings.properties	Thu Feb 07 18:33:33 2013 +0100
@@ -0,0 +1,8 @@
+SCHEDULER_TAB=Scheduler
+HEADER_LABEL=FreeJav DevRoom Schedule
+PRESENTATION_TITLE=Title
+SPEAKERS=Speakers
+LOAD_SCHEDULE=Load Presentations
+PRESENTATION_MODE=Presentation Mode
+CLOCK_VIEW_TITLE=Clock
+PRESENTATION_SUMMARY=Full Schedule
Binary file agent/src/main/resources/com/redhat/thermostat/tutorial/schedule/client/common/presentation.png has changed
--- a/client-common/src/main/java/com/redhat/thermostat/tutorial/schedule/client/common/ClockView.java	Thu Feb 07 18:33:27 2013 +0100
+++ b/client-common/src/main/java/com/redhat/thermostat/tutorial/schedule/client/common/ClockView.java	Thu Feb 07 18:33:33 2013 +0100
@@ -80,4 +80,9 @@
      * Display the given {@link ClockTime} in the current {@code ClockView}.
      */
     public abstract void displayTime(ClockTime time);
+    
+    /**
+     * Display the given {@link PresentationInfo} in the current {@code ClockView}.
+     */
+    public abstract void displayPresentation(PresentationInfo info);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client-common/src/main/java/com/redhat/thermostat/tutorial/schedule/client/common/PresentationInfo.java	Thu Feb 07 18:33:33 2013 +0100
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2012, 2013 Red Hat, Inc.
+ * 
+ * This file is part of Thermostat.
+ * 
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ * 
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ * 
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ * 
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.tutorial.schedule.client.common;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+/**
+ */
+public class PresentationInfo {
+
+    private String title;
+    private List<String> speakers = new ArrayList<>();
+    private Date startDate;
+    private Date endDate;
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public Date getEndDate() {
+        return endDate;
+    }
+
+    public void setEndDate(Date endDate) {
+        this.endDate = endDate;
+    }
+
+    public Date getStartDate() {
+        return startDate;
+    }
+
+    public void setStartDate(Date startDate) {
+        this.startDate = startDate;
+    }
+
+    public List<String> getSpeakers() {
+        return speakers;
+    }
+    
+    public void addSpeaker(String speaker) {
+        this.speakers.add(speaker);
+    }
+    
+    @Override
+    public String toString() {
+        return "[" + title + " - " +  Arrays.toString(speakers.toArray()) + " - " + startDate + " - " + endDate + "]";
+    }
+}
--- a/client-controllers/.classpath	Thu Feb 07 18:33:27 2013 +0100
+++ b/client-controllers/.classpath	Thu Feb 07 18:33:33 2013 +0100
@@ -12,6 +12,11 @@
 			<attribute name="maven.pomderived" value="true"/>
 		</attributes>
 	</classpathentry>
+	<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
 		<attributes>
 			<attribute name="maven.pomderived" value="true"/>
--- a/client-controllers/.settings/org.eclipse.core.resources.prefs	Thu Feb 07 18:33:27 2013 +0100
+++ b/client-controllers/.settings/org.eclipse.core.resources.prefs	Thu Feb 07 18:33:33 2013 +0100
@@ -1,4 +1,5 @@
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
 encoding//src/test/java=UTF-8
 encoding/<project>=UTF-8
--- a/client-controllers/pom.xml	Thu Feb 07 18:33:27 2013 +0100
+++ b/client-controllers/pom.xml	Thu Feb 07 18:33:33 2013 +0100
@@ -111,6 +111,13 @@
         <type>jar</type>
     </dependency>
     
+    <dependency>
+        <groupId>com.redhat.thermostat.tutorial.schedule</groupId>
+        <artifactId>thermostat-tutorial-storage-common</artifactId>
+        <version>${project.version}</version>
+        <type>jar</type>
+    </dependency>
+    
   </dependencies>
 
   <build>
--- a/client-controllers/src/main/java/com/redhat/thermostat/tutorial/schedule/client/controller/impl/ClockController.java	Thu Feb 07 18:33:27 2013 +0100
+++ b/client-controllers/src/main/java/com/redhat/thermostat/tutorial/schedule/client/controller/impl/ClockController.java	Thu Feb 07 18:33:33 2013 +0100
@@ -42,14 +42,19 @@
 import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
 import com.redhat.thermostat.common.ApplicationCache;
+import com.redhat.thermostat.common.ApplicationService;
 import com.redhat.thermostat.common.Timer;
 
 import com.redhat.thermostat.tutorial.schedule.client.common.ClockView;
 import com.redhat.thermostat.tutorial.schedule.client.common.ClockView.ClockViewAction;
+import com.redhat.thermostat.tutorial.schedule.client.common.PresentationInfo;
 import com.redhat.thermostat.tutorial.schedule.client.common.clock.ClockTime;
+import java.util.ArrayList;
 import java.util.Calendar;
 
 import java.util.Date;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -62,15 +67,23 @@
     private static final String SHOW_DETAILS_KEY = "SHOW_DETAILS_KEY";
     private static final String PRESENTATION_MODE_KEY = "PRESENTATION_MODE_KEY";
 
-    private volatile boolean presentationMode;
+    private boolean presentationMode;
     
     private ClockView clockView;
     private ApplicationCache applicationCache;
+    private ExecutorService executor;
     
-    public ClockController(ClockView clockView, ApplicationCache applicationCache) {
+    private List<PresentationInfo> presentations;
+    
+    private SchedulerMainController mainController;
+    
+    public ClockController(ClockView clockView, ApplicationService service, SchedulerMainController mainController) {
+        
+        this.mainController = mainController;
         
         this.clockView = clockView;
-        this.applicationCache = applicationCache;
+        this.applicationCache = service.getApplicationCache();
+        this.executor = service.getApplicationExecutor();
         
         clockView.displayPresentationDetails(isShowDetails());
         presentationMode = isPresentationMode();
@@ -90,47 +103,130 @@
     }
     
     private void togglePresentationMode() {
+        boolean _presentationMode = false;
         synchronized (LOCK) {
             presentationMode = !presentationMode;
-            applicationCache.addAttribute(PRESENTATION_MODE_KEY, presentationMode);
-            clockView.displayPresentationDetails(presentationMode);
+            _presentationMode = presentationMode;
+        }
+        
+        applicationCache.addAttribute(PRESENTATION_MODE_KEY, _presentationMode);
+        clockView.displayPresentationDetails(_presentationMode);
+        if (_presentationMode) {
+            executor.execute(new CurrentPresentationInfo());
+        }
+    }
+    
+    private class CurrentPresentationInfo implements Runnable {
+        @Override
+        public void run() {
+            String iCalText = mainController.getSchedule();
+            List<PresentationInfo> _presentations = getPresentations(iCalText);
+            synchronized (LOCK) {
+                presentations = _presentations;
+            }
         }
     }
     
+    private List<PresentationInfo> getPresentations(String iCalText) {
+        ICalParser parser = new ICalParser();
+        return parser.parse(iCalText);
+    }
+    
+    private void setClock(long nowMillis, boolean displayHour) {
+
+        Date now = new Date(nowMillis);
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(now);
+
+        int hour = calendar.get(Calendar.HOUR);
+        int minute = calendar.get(Calendar.MINUTE);
+        int second = calendar.get(Calendar.SECOND);
+
+        ClockTime time = new ClockTime();
+        if (displayHour) {
+            time.setHour(hour);
+        }
+        
+        time.setMinute(minute);
+        time.setSecond(second);
+
+        clockView.displayTime(time);
+    }
+    
+    private void setClock(long nowMillis) {
+        
+        setClock(nowMillis, true);
+    }
+    
+    // for debugging
+//    private long currentTime = 0;
     void initController(final Timer timer) {
         timer.setDelay(1);
         timer.setTimeUnit(TimeUnit.SECONDS);
         
+//        Calendar calendar = Calendar.getInstance();
+//        calendar.set(2013, 2, 2, 14, 39, 00);
+//        currentTime = calendar.getTime().getTime();
+        
         // don't need exact seconds since we calculate correct timing each time
         timer.setSchedulingType(Timer.SchedulingType.FIXED_RATE);
         timer.setAction(new Runnable() {
             @Override
-            public void run() {
+            public void run() {                
                 boolean _presentationMode = false;
                 synchronized (LOCK) {
                     _presentationMode = ClockController.this.presentationMode;
                 }
                 
+                Date date = new Date(System.currentTimeMillis());
+                long currentTime = date.getTime();
+
+//                currentTime += 1000;
+                
                 if (!_presentationMode) {
                     // normal clock mode, so we just show the current time
-                    long nowMillis = System.currentTimeMillis();
-                    Date now = new Date(nowMillis);
-                    Calendar calendar = Calendar.getInstance();
-                    calendar.setTime(now);
-                    
-                    int hour = calendar.get(Calendar.HOUR);
-                    int minute = calendar.get(Calendar.MINUTE);
-                    int second = calendar.get(Calendar.SECOND);
-                    
-                    ClockTime time = new ClockTime();
-                    time.setHour(hour);
-                    time.setMinute(minute);
-                    time.setSecond(second);
-                    
-                    clockView.displayTime(time);
+                    clockView.displayPresentationDetails(false);
+                    setClock(System.currentTimeMillis());
+                } else {
+                    List<PresentationInfo> _presentations = null;
+                    synchronized (LOCK) {
+                        _presentations = presentations;
+                    }
+                    if (_presentations != null) {
+                        PresentationInfo found = null;
+                        for (PresentationInfo info : _presentations) {
+                            
+                            long now = currentTime;
+                            long startDate = info.getStartDate().getTime();
+                            long stopTime = info.getEndDate().getTime();
+
+                            if (now > startDate && now < stopTime) {
+                                // found
+                                found = info;
+                                break;
+                            }
+                        }
+                        
+                        if (found == null) {
+                            clockView.displayPresentationDetails(false);
+                            setClock(currentTime);
+//                            currentTime += 1000 * 60 * 9;
+                            
+                        } else {
+                            clockView.displayPresentationDetails(true);
+
+                            long stopTime = found.getEndDate().getTime();
+                            long nowMillis = stopTime - currentTime;
+
+                            setClock(nowMillis, false);
+                            
+                            clockView.displayPresentation(found);
+                        }
+                    }
                 }
             }
         });
+
         clockView.addActionListener(new ActionListener<BasicView.Action>() {
             @Override
             public void actionPerformed(ActionEvent<Action> actionEvent) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client-controllers/src/main/java/com/redhat/thermostat/tutorial/schedule/client/controller/impl/ICalParser.java	Thu Feb 07 18:33:33 2013 +0100
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2012, 2013 Red Hat, Inc.
+ * 
+ * This file is part of Thermostat.
+ * 
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ * 
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ * 
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ * 
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.tutorial.schedule.client.controller.impl;
+
+import com.redhat.thermostat.tutorial.schedule.client.common.PresentationInfo;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+
+import java.util.List;
+
+/**
+ */
+public class ICalParser {
+
+    private List<String> lines;
+
+    public List<PresentationInfo> parse(String contents) {
+        lines = new ArrayList<>();
+        lines.addAll(Arrays.asList(contents.split("\n")));
+
+        List<PresentationInfo> results = new ArrayList<>();
+
+        String line = getNextLine();
+        while (line != null) {
+            if (line.equals("BEGIN:VEVENT")) {
+                results.add(parseEvent());
+            }
+            line = getNextLine();
+        }
+
+        return results;
+    }
+
+    private PresentationInfo parseEvent() {
+        PresentationInfo info = new PresentationInfo();
+
+        String line = getNextLine();
+        while (!(line.equals("END:VEVENT"))) {
+            if (line.startsWith("DTSTART:")) {
+                String dateString = line.split(":")[1];
+                info.setStartDate(parseDate(dateString));
+            } else if (line.startsWith("DTEND:")) {
+                String dateString = line.split(":")[1];
+                info.setEndDate(parseDate(dateString));
+            } else if (line.startsWith("SUMMARY:")) {
+                info.setTitle(line.split(":")[1]);
+            } else if (line.startsWith("ATTENDEE;")) {
+                int nameStart = line.indexOf("CN=\"") + 4;
+                int nameEnd = line.indexOf("\"", nameStart + 1);
+                info.addSpeaker(line.substring(nameStart, nameEnd));
+            }
+            line = getNextLine();
+        }
+        return info;
+    }
+
+    private Date parseDate(String dateString) {
+        int year = Integer.valueOf(dateString.substring(0, 4));
+        int month = Integer.valueOf(dateString.substring(4, 6)) - 1;
+        int day = Integer.valueOf(dateString.substring(6, 8));
+        int hours = Integer.valueOf(dateString.substring(9, 11));
+        int minutes = Integer.valueOf(dateString.substring(11, 13));
+        int seconds = Integer.valueOf(dateString.substring(13, 15));
+        
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(year, month, day, hours, minutes, seconds);
+        
+        return calendar.getTime();
+    }
+
+    private String getNextLine() {
+        if (lines.isEmpty()) {
+            return null;
+        }
+        return lines.remove(0).trim();
+    }
+}
\ No newline at end of file
--- a/client-controllers/src/main/java/com/redhat/thermostat/tutorial/schedule/client/controller/impl/SchedulerInformationService.java	Thu Feb 07 18:33:27 2013 +0100
+++ b/client-controllers/src/main/java/com/redhat/thermostat/tutorial/schedule/client/controller/impl/SchedulerInformationService.java	Thu Feb 07 18:33:33 2013 +0100
@@ -43,6 +43,7 @@
 import com.redhat.thermostat.common.ApplicationService;
 import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.tutorial.schedule.client.common.SchedulerViewProvider;
+import com.redhat.thermostat.tutorial.schedule.storage.SchedulerDAO;
 
 /**
  * Implementation of an {@code InformationService} for {@code HostRef}s.
@@ -60,10 +61,12 @@
 
     private ApplicationService applicationService;
     private SchedulerViewProvider schedulerProvider;
+    private SchedulerDAO dao;
     
-    public SchedulerInformationService(ApplicationService applicationService, SchedulerViewProvider schedulerProvider) {
+    public SchedulerInformationService(ApplicationService applicationService, SchedulerViewProvider schedulerProvider, SchedulerDAO dao) {
         this.applicationService = applicationService;
         this.schedulerProvider = schedulerProvider;
+        this.dao = dao;
     }
 
     @Override
@@ -73,7 +76,7 @@
 
     @Override
     public InformationServiceController<HostRef> getInformationServiceController(HostRef ref) {
-        return new SchedulerMainController(applicationService, schedulerProvider);
+        return new SchedulerMainController(applicationService, schedulerProvider, dao);
     }
 
     @Override
--- a/client-controllers/src/main/java/com/redhat/thermostat/tutorial/schedule/client/controller/impl/SchedulerMainController.java	Thu Feb 07 18:33:27 2013 +0100
+++ b/client-controllers/src/main/java/com/redhat/thermostat/tutorial/schedule/client/controller/impl/SchedulerMainController.java	Thu Feb 07 18:33:33 2013 +0100
@@ -45,7 +45,10 @@
 import com.redhat.thermostat.tutorial.schedule.client.common.SchedulerView;
 import com.redhat.thermostat.tutorial.schedule.client.common.SchedulerView.SchedulerViewAction;
 import com.redhat.thermostat.tutorial.schedule.client.common.SchedulerViewProvider;
+import com.redhat.thermostat.tutorial.schedule.storage.SchedulerDAO;
 import java.io.File;
+import java.io.InputStream;
+import java.util.Scanner;
 
 /**
  * Main controller for the Scheduler plugin.
@@ -53,9 +56,16 @@
 public class SchedulerMainController implements InformationServiceController<HostRef> {
 
     private SchedulerView view;
+    private SchedulerDAO dao;
+    private ApplicationService service;
+    private ClockController clockController;
     
-    SchedulerMainController(ApplicationService applicationService, SchedulerViewProvider schedulerProvider) {
+    private volatile String lastScheduleName;
+    
+    SchedulerMainController(ApplicationService applicationService, SchedulerViewProvider schedulerProvider, SchedulerDAO dao) {
 
+        this.service = applicationService;
+        this.dao = dao;
         view = schedulerProvider.createView();
         
         view.addSchedulerViewActionListener(new ActionListener<SchedulerView.SchedulerViewAction>() {
@@ -63,20 +73,35 @@
             public void actionPerformed(ActionEvent<SchedulerViewAction> actionEvent) {
                 switch (actionEvent.getActionId()) {
                 case LOAD_SCHEDULE:
-                    File payload = (File) actionEvent.getPayload();
-                    System.err.println("file: " + payload);
+                    storeDocument((File) actionEvent.getPayload());
                     break;
-                    
                 default:
                     break;
                 }
             }
         });
         
-        ClockController clockController = new ClockController(view.getClockView(), applicationService.getApplicationCache());
-        clockController.initController(applicationService.getTimerFactory().createTimer());
+        clockController = new ClockController(view.getClockView(), service, this);
+        clockController.initController(service.getTimerFactory().createTimer());
     }
 
+    public String getSchedule() {
+        String _lastScheduleName = lastScheduleName;
+        
+        InputStream stream = dao.load(_lastScheduleName);
+        Scanner text = new Scanner(stream).useDelimiter("\\A");
+        return text.hasNext() ? text.next() : "";
+    }
+
+    private void storeDocument(final File document) {
+        service.getApplicationExecutor().execute(new Runnable() {
+            @Override
+            public void run() {
+                lastScheduleName = dao.store(document);
+            }
+        });
+    }
+    
     @Override
     public String getLocalizedName() {
         return "Scheduler";
--- a/client-controllers/src/main/java/com/redhat/thermostat/tutorial/schedule/client/controller/osgi/Activator.java	Thu Feb 07 18:33:27 2013 +0100
+++ b/client-controllers/src/main/java/com/redhat/thermostat/tutorial/schedule/client/controller/osgi/Activator.java	Thu Feb 07 18:33:33 2013 +0100
@@ -37,16 +37,22 @@
 package com.redhat.thermostat.tutorial.schedule.client.controller.osgi;
 
 import com.redhat.thermostat.client.core.InformationService;
+
 import com.redhat.thermostat.common.ApplicationService;
 import com.redhat.thermostat.common.Constants;
 import com.redhat.thermostat.common.MultipleServiceTracker;
 import com.redhat.thermostat.common.MultipleServiceTracker.Action;
+
 import com.redhat.thermostat.storage.core.HostRef;
+
 import com.redhat.thermostat.tutorial.schedule.client.common.SchedulerViewProvider;
 import com.redhat.thermostat.tutorial.schedule.client.controller.impl.SchedulerInformationService;
+import com.redhat.thermostat.tutorial.schedule.storage.SchedulerDAO;
+
 import java.util.Dictionary;
 import java.util.Hashtable;
 import java.util.Map;
+
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
@@ -61,6 +67,7 @@
         Class[] classes = new Class[]{
             ApplicationService.class,
             SchedulerViewProvider.class,
+            SchedulerDAO.class,
         };
         
         Action action = new Action() {
@@ -70,8 +77,9 @@
             public void dependenciesAvailable(Map<String, Object> services) {
                 ApplicationService applicationService = (ApplicationService) services.get(ApplicationService.class.getName());
                 SchedulerViewProvider schedulerProvider = (SchedulerViewProvider) services.get(SchedulerViewProvider.class.getName());
+                SchedulerDAO dao = (SchedulerDAO) services.get(SchedulerDAO.class.getName());
                 
-                InformationService<HostRef> infoService = new SchedulerInformationService(applicationService, schedulerProvider);
+                InformationService<HostRef> infoService = new SchedulerInformationService(applicationService, schedulerProvider, dao);
                 Dictionary<String, String> properties = new Hashtable<>();
                 
                 // this line is important, since is the actual place we inform
--- a/client-swing/.classpath	Thu Feb 07 18:33:27 2013 +0100
+++ b/client-swing/.classpath	Thu Feb 07 18:33:33 2013 +0100
@@ -12,6 +12,11 @@
 			<attribute name="maven.pomderived" value="true"/>
 		</attributes>
 	</classpathentry>
+	<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
 		<attributes>
 			<attribute name="maven.pomderived" value="true"/>
--- a/client-swing/.settings/org.eclipse.core.resources.prefs	Thu Feb 07 18:33:27 2013 +0100
+++ b/client-swing/.settings/org.eclipse.core.resources.prefs	Thu Feb 07 18:33:33 2013 +0100
@@ -1,4 +1,5 @@
 eclipse.preferences.version=1
 encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
 encoding//src/test/java=UTF-8
 encoding/<project>=UTF-8
--- a/client-swing/src/main/java/com/redhat/thermostat/tutorial/schedule/client/swing/impl/ContentPanel.java	Thu Feb 07 18:33:27 2013 +0100
+++ b/client-swing/src/main/java/com/redhat/thermostat/tutorial/schedule/client/swing/impl/ContentPanel.java	Thu Feb 07 18:33:33 2013 +0100
@@ -36,7 +36,6 @@
 
 package com.redhat.thermostat.tutorial.schedule.client.swing.impl;
 
-import com.redhat.thermostat.client.swing.components.HeaderPanel;
 import com.redhat.thermostat.tutorial.schedule.client.common.clock.ClockTime;
 import com.redhat.thermostat.tutorial.schedule.client.swing.impl.clock.ClockPanel;
 import com.redhat.thermostat.tutorial.schedule.client.swing.impl.scheduler.CurrentPresentationPanel;
@@ -78,64 +77,8 @@
     public ClockPanel getClock() {
         return clock;
     }
-    
-    public static final void main(String[] args) {
-        SwingUtilities.invokeLater(new Runnable() {
-            @Override
-            public void run() {
-                JFrame frame = new JFrame();
-                frame.setSize(500, 500);
-                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 
-                ClockTime time = new ClockTime();
-                time.setSecond(10);
-                time.setMinute(59);
-                time.setHour(11);
-
-                final ContentPanel panel = new ContentPanel();
-                panel.getClock().setTime(time);
-                panel.displayOnAirInformation(true);
-                Timer timer = new Timer(1000, new ActionListener() {
-                    @Override
-                    public void actionPerformed(ActionEvent e) {
-                        
-                        ClockTime time = panel.getClock().getTime();
-                        
-                        int second = time.getSecond();
-                        int minute = time.getMinute();
-                        int hour = time.getHour();
-
-                        second -= 1;
-                        if (second < 0) {
-                            second = 60;
-
-                            minute -= 1;
-                            if (minute < 0) {
-                                minute = 60;
-                                hour -= 1;
-                                if (hour < 0) {
-                                    hour = 12;
-                                }
-                            }
-
-                        }
-
-                        time.setSecond(second);
-                        time.setMinute(minute);
-                        time.setHour(hour);
-
-                        panel.clock.setTime(time);
-                        
-                        panel.clock.repaint();
-                    }
-                });
-                timer.setInitialDelay(1000);
-                timer.start();
-
-                frame.getContentPane().add(panel);
-
-                frame.setVisible(true);
-            }
-        });
-    }    
+    public CurrentPresentationPanel getOnAir() {
+        return onAir;
+    }
 }
--- a/client-swing/src/main/java/com/redhat/thermostat/tutorial/schedule/client/swing/impl/SwingClockView.java	Thu Feb 07 18:33:27 2013 +0100
+++ b/client-swing/src/main/java/com/redhat/thermostat/tutorial/schedule/client/swing/impl/SwingClockView.java	Thu Feb 07 18:33:33 2013 +0100
@@ -39,18 +39,20 @@
 import com.redhat.thermostat.client.core.views.BasicView;
 import com.redhat.thermostat.client.swing.ComponentVisibleListener;
 import com.redhat.thermostat.client.swing.SwingComponent;
-import com.redhat.thermostat.client.swing.components.ActionButton;
 import com.redhat.thermostat.client.swing.components.ActionToggleButton;
 import com.redhat.thermostat.client.swing.components.HeaderPanel;
 import com.redhat.thermostat.client.swing.components.ToolbarButton;
 import com.redhat.thermostat.tutorial.schedule.client.common.ClockView;
 import com.redhat.thermostat.tutorial.schedule.client.common.IconResources;
+import com.redhat.thermostat.tutorial.schedule.client.common.PresentationInfo;
 import com.redhat.thermostat.tutorial.schedule.client.common.clock.ClockTime;
 import com.redhat.thermostat.tutorial.schedule.client.common.locale.LocaleResources;
+import com.redhat.thermostat.tutorial.schedule.client.swing.impl.scheduler.PresentationInfoPanel;
 import java.awt.Component;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import javax.swing.ImageIcon;
+import javax.swing.SwingUtilities;
 
 /**
  */
@@ -89,8 +91,30 @@
     }
 
     @Override
-    public void displayPresentationDetails(boolean display) {
-        content.displayOnAirInformation(display);
+    public void displayPresentationDetails(final boolean display) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                content.displayOnAirInformation(display);
+                content.repaint();
+            }
+        });
+    }
+
+    @Override
+    public void displayPresentation(final PresentationInfo info) {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                PresentationInfoPanel infoPanel = content.getOnAir().getInfo();
+                infoPanel.setTitle(info.getTitle());
+                infoPanel.clearSpeakers();
+                for (String speaker : info.getSpeakers()) {
+                    infoPanel.addSpeaker(speaker);
+                }
+                content.repaint();
+            }
+        });
     }
 
     @Override
--- a/client-swing/src/main/java/com/redhat/thermostat/tutorial/schedule/client/swing/impl/scheduler/CurrentPresentationPanel.java	Thu Feb 07 18:33:27 2013 +0100
+++ b/client-swing/src/main/java/com/redhat/thermostat/tutorial/schedule/client/swing/impl/scheduler/CurrentPresentationPanel.java	Thu Feb 07 18:33:33 2013 +0100
@@ -57,10 +57,6 @@
         setBackground(ClockUtils.PANEL_BG);
         
         info = new PresentationInfoPanel();
-        info.setTitle("Thermostat: The road from 0.1 to 1.0, a success story (in progress)");
-
-        info.addSpeaker("Mario Torre");
-        info.addSpeaker("Roman Kennke");
         
         add(Box.createRigidArea(new Dimension(0, 100)), BorderLayout.NORTH);
         add(Box.createRigidArea(new Dimension(50, 50)), BorderLayout.WEST);
@@ -69,4 +65,8 @@
 
         add(info, BorderLayout.CENTER);
     }
+
+    public PresentationInfoPanel getInfo() {
+        return info;
+    }
 }
--- a/client-swing/src/main/java/com/redhat/thermostat/tutorial/schedule/client/swing/impl/scheduler/PresentationInfoPanel.java	Thu Feb 07 18:33:27 2013 +0100
+++ b/client-swing/src/main/java/com/redhat/thermostat/tutorial/schedule/client/swing/impl/scheduler/PresentationInfoPanel.java	Thu Feb 07 18:33:33 2013 +0100
@@ -42,6 +42,8 @@
 import com.redhat.thermostat.tutorial.schedule.client.swing.impl.ClockUtils;
 import java.awt.Component;
 import java.awt.Dimension;
+import java.util.ArrayList;
+import java.util.List;
 import javax.swing.Box;
 import javax.swing.BoxLayout;
 import javax.swing.JLabel;
@@ -61,6 +63,8 @@
 
     private JPanel presentationPanel;
     
+    private List<JLabel> speakers;
+    
     public PresentationInfoPanel() {
         setBackground(ClockUtils.PANEL_BG);
 
@@ -68,6 +72,8 @@
         
         setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
         
+        speakers = new ArrayList<>();
+        
         titleCaption = new JLabel(ClockUtils.localize(LocaleResources.PRESENTATION_TITLE));
         titleCaption.setForeground(ClockUtils.PANEL_FG);
         titleCaption.setBackground(ClockUtils.PANEL_BG);
@@ -103,6 +109,7 @@
         presentationPanel.add(Box.createRigidArea(new Dimension(0, 20)));
         presentationPanel.add(speakersCaption);
         presentationPanel.add(Box.createRigidArea(new Dimension(0, 5)));
+        
         add(presentationPanel);
     }
 
@@ -123,7 +130,16 @@
         speakerLabel.setFont(speakerLabel.getFont().deriveFont(Font.NORMAL));
 
         speakerLabel.setIcon(new BulletIcon());
+        speakers.add(speakerLabel);
+        
         presentationPanel.add(speakerLabel);
+        presentationPanel.revalidate();
         repaint();
     }
+
+    public void clearSpeakers() {
+        for (JLabel speaker : speakers) {
+            presentationPanel.remove(speaker);
+        }
+    }
 }
--- a/copy_jars.sh	Thu Feb 07 18:33:27 2013 +0100
+++ b/copy_jars.sh	Thu Feb 07 18:33:33 2013 +0100
@@ -4,7 +4,13 @@
     exit -1
 fi
 
-cp -v ./client-controllers/target/thermostat-tutorial-client-controllers-0.0.1-SNAPSHOT.jar $THERMOSTAT_DEV_HOME/distribution/target/libs
-cp -v ./client-swing/target/thermostat-tutorial-client-swing-0.0.1-SNAPSHOT.jar $THERMOSTAT_DEV_HOME/distribution/target/libs
-cp -v ./client-common/target/thermostat-tutorial-client-common-0.0.1-SNAPSHOT.jar $THERMOSTAT_DEV_HOME/distribution/target/libs
+PLUGIN=$THERMOSTAT_DEV_HOME/distribution/target/plugins/schedule/
 
+mkdir -p $PLUGIN
+cp -v ./client-controllers/target/thermostat-tutorial-client-controllers-0.0.1-SNAPSHOT.jar $PLUGIN
+cp -v ./client-swing/target/thermostat-tutorial-client-swing-0.0.1-SNAPSHOT.jar $PLUGIN
+cp -v ./client-common/target/thermostat-tutorial-client-common-0.0.1-SNAPSHOT.jar $PLUGIN
+cp -v ./agent/target/thermostat-tutorial-agent-0.0.1-SNAPSHOT.jar $PLUGIN
+cp -v ./storage-common/target/thermostat-tutorial-storage-common-0.0.1-SNAPSHOT.jar $PLUGIN
+cp -v ./plugin.conf $PLUGIN
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugin.conf	Thu Feb 07 18:33:33 2013 +0100
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<plugin>
+  <commands>
+    <existing>
+      <name>gui</name>
+      <bundles>
+	thermostat-tutorial-client-swing-0.0.1-SNAPSHOT.jar,
+	thermostat-tutorial-client-common-0.0.1-SNAPSHOT.jar,
+	thermostat-tutorial-storage-common-0.0.1-SNAPSHOT.jar,
+	thermostat-tutorial-client-controllers-0.0.1-SNAPSHOT.jar
+      </bundles>
+    </existing>
+ </commands>
+</plugin>
--- a/pom.xml	Thu Feb 07 18:33:27 2013 +0100
+++ b/pom.xml	Thu Feb 07 18:33:33 2013 +0100
@@ -91,6 +91,8 @@
     <module>client-common</module>
     <module>client-controllers</module>
     <module>client-swing</module>
+    <module>agent</module>
+    <module>storage-common</module>
   </modules>
 
   <build>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage-common/pom.xml	Thu Feb 07 18:33:33 2013 +0100
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+
+ Copyright 2012, 2013 Red Hat, Inc.
+
+ This file is part of Thermostat.
+
+ Thermostat is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ Thermostat is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Thermostat; see the file COPYING.  If not see
+ <http://www.gnu.org/licenses />.
+
+ Linking this code with other modules is making a combined work
+ based on this code.  Thus, the terms and conditions of the GNU
+ General Public License cover the whole combination.
+
+ As a special exception, the copyright holders of this code give
+ you permission to link this code with independent modules to
+ produce an executable, regardless of the license terms of these
+ independent modules, and to copy and distribute the resulting
+ executable under terms of your choice, provided that you also
+ meet, for each linked independent module, the terms and conditions
+ of the license of that module.  An independent module is a module
+ which is not derived from or based on this code.  If you modify
+ this code, you may extend this exception to your version of the
+ library, but you are not obligated to do so.  If you do not wish
+ to do so, delete this exception statement from your version.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>com.redhat.thermostat.tutorial.schedule</groupId>
+    <artifactId>thermostat-tutorial</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>thermostat-tutorial-storage-common</artifactId>
+  <packaging>bundle</packaging>
+
+  <name>Thermostat Schedule Storage Common</name>
+
+  <dependencies>
+      
+      <!-- osgi and test dependencies -->
+      
+      <dependency>
+          <groupId>junit</groupId>
+          <artifactId>junit</artifactId>
+          <scope>test</scope>
+      </dependency>
+    
+      <dependency>
+          <groupId>org.mockito</groupId>
+          <artifactId>mockito-core</artifactId>
+          <scope>test</scope>
+      </dependency>
+        
+      <dependency>
+          <groupId>org.osgi</groupId>
+          <artifactId>org.osgi.core</artifactId>
+          <scope>provided</scope>
+      </dependency>
+    
+      <dependency>
+          <groupId>org.osgi</groupId>
+          <artifactId>org.osgi.compendium</artifactId>
+          <scope>provided</scope>
+      </dependency>
+
+      <!-- thermostat specific dependencies -->
+    
+      <dependency>
+          <groupId>com.redhat.thermostat</groupId>
+          <artifactId>thermostat-client-core</artifactId>
+          <type>jar</type>
+      </dependency>
+      
+      <dependency>
+          <groupId>com.redhat.thermostat</groupId>
+          <artifactId>thermostat-common-core</artifactId>
+          <type>jar</type>
+      </dependency>
+    
+      <!-- plugin specific dependencies -->
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor>
+            <Bundle-SymbolicName>com.redhat.thermostat.tutorial.schedule.storage</Bundle-SymbolicName>
+            <Bundle-Activator>com.redhat.thermostat.tutorial.schedule.storage.osgi.Activator</Bundle-Activator>
+            <Export-Package>
+                com.redhat.thermostat.tutorial.schedule.storage,
+            </Export-Package>
+            <Private-Package>
+                com.redhat.thermostat.tutorial.schedule.storage.osgi,
+                com.redhat.thermostat.tutorial.schedule.storage.impl,
+            </Private-Package>
+            <!-- Do not autogenerate uses clauses in Manifests -->
+            <_nouses>true</_nouses>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage-common/src/main/java/com/redhat/thermostat/tutorial/schedule/storage/SchedulerDAO.java	Thu Feb 07 18:33:33 2013 +0100
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2012, 2013 Red Hat, Inc.
+ * 
+ * This file is part of Thermostat.
+ * 
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ * 
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ * 
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ * 
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.tutorial.schedule.storage;
+
+import com.redhat.thermostat.storage.core.Category;
+import com.redhat.thermostat.storage.core.Key;
+import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.tutorial.schedule.storage.impl.Schedule;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ */
+public class SchedulerDAO {
+
+    static final Key<String> scheduleID = new Key<String>("scheduleID", false);
+
+    private static final Category<Schedule> schedulerCategory =
+            new Category<>("tutorial-scheduler", Schedule.class, Key.AGENT_ID, Key.TIMESTAMP, scheduleID);
+    
+    private Storage storage;
+
+    public SchedulerDAO(Storage storage) {
+        this.storage = storage;
+        storage.registerCategory(schedulerCategory);
+    }
+
+    public String store(File document) {
+        try {
+            long now = System.currentTimeMillis();
+            String name = "fosdem-schedule" + "-" + now;
+            // a real plugin would make this configuratble
+            storage.saveFile(name, new FileInputStream(document));
+            return name;
+            
+        } catch (FileNotFoundException ex) {
+            Logger.getLogger(SchedulerDAO.class.getName()).log(Level.SEVERE, null, ex);
+            return null;
+        }
+    }
+
+    public InputStream load(String name) {
+        return storage.loadFile(name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage-common/src/main/java/com/redhat/thermostat/tutorial/schedule/storage/impl/Schedule.java	Thu Feb 07 18:33:33 2013 +0100
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012, 2013 Red Hat, Inc.
+ * 
+ * This file is part of Thermostat.
+ * 
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ * 
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ * 
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ * 
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.tutorial.schedule.storage.impl;
+
+import com.redhat.thermostat.storage.core.Persist;
+import com.redhat.thermostat.storage.model.BasePojo;
+import com.redhat.thermostat.storage.model.TimeStampedPojo;
+
+/**
+ */
+public class Schedule extends BasePojo implements TimeStampedPojo {
+    
+    private long timeStamp;
+    private String scheduleID;
+    
+    @Override
+    @Persist
+    public long getTimeStamp() {
+        return this.timeStamp;
+    }
+
+    @Persist
+    public void setTimeStamp(long timeStamp) {
+        this.timeStamp = timeStamp;
+    }
+
+    @Persist
+    public void setScheduleID(String scheduleID) {
+        this.scheduleID = scheduleID;
+    }
+
+    @Persist
+    public String getScheduleID() {
+        return scheduleID;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage-common/src/main/java/com/redhat/thermostat/tutorial/schedule/storage/osgi/Activator.java	Thu Feb 07 18:33:33 2013 +0100
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012, 2013 Red Hat, Inc.
+ * 
+ * This file is part of Thermostat.
+ * 
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ * 
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ * 
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ * 
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.tutorial.schedule.storage.osgi;
+
+import com.redhat.thermostat.storage.core.Storage;
+import com.redhat.thermostat.tutorial.schedule.storage.SchedulerDAO;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Activator that register the Scheduler DAO implementation. 
+ */
+public class Activator implements BundleActivator {
+    
+    @SuppressWarnings("rawtypes")
+    private ServiceRegistration reg;
+    
+    @Override
+    public void start(final BundleContext context) throws Exception {
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        ServiceTracker tracker = new ServiceTracker(context, Storage.class.getName(), null) {
+            @Override
+            public Object addingService(ServiceReference reference) {
+                Storage storage = (Storage) context.getService(reference);
+                SchedulerDAO schedulerDAO = new SchedulerDAO(storage);
+                reg = context.registerService(SchedulerDAO.class.getName(), schedulerDAO, null);
+                return super.addingService(reference);
+            }
+        };
+        tracker.open();
+    }
+
+    @Override
+    public void stop(BundleContext bc) throws Exception {
+        if (reg != null) {
+            reg.unregister();
+        }
+    }
+}
Binary file storage-common/src/main/resources/com/redhat/thermostat/tutorial/schedule/client/common/load.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/storage-common/src/main/resources/com/redhat/thermostat/tutorial/schedule/client/common/locale/strings.properties	Thu Feb 07 18:33:33 2013 +0100
@@ -0,0 +1,8 @@
+SCHEDULER_TAB=Scheduler
+HEADER_LABEL=FreeJav DevRoom Schedule
+PRESENTATION_TITLE=Title
+SPEAKERS=Speakers
+LOAD_SCHEDULE=Load Presentations
+PRESENTATION_MODE=Presentation Mode
+CLOCK_VIEW_TITLE=Clock
+PRESENTATION_SUMMARY=Full Schedule
Binary file storage-common/src/main/resources/com/redhat/thermostat/tutorial/schedule/client/common/presentation.png has changed