org.openhab.persistence.caldav.internal.CaldavPersistenceService.java Source code

Java tutorial

Introduction

Here is the source code for org.openhab.persistence.caldav.internal.CaldavPersistenceService.java

Source

/**
 * Copyright (c) 2010-2016 by the respective copyright holders.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 */
package org.openhab.persistence.caldav.internal;

import static org.openhab.persistence.caldav.internal.CaldavConfiguration.calendarId;
import static org.openhab.persistence.caldav.internal.CaldavConfiguration.duration;
import static org.openhab.persistence.caldav.internal.CaldavConfiguration.singleEvents;
import static org.openhab.persistence.caldav.internal.CaldavConfiguration.futureOffset;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;

import org.joda.time.DateTime;
import org.openhab.core.items.Item;
import org.openhab.core.items.ItemNotFoundException;
import org.openhab.core.items.ItemRegistry;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.persistence.FilterCriteria;
import org.openhab.core.persistence.HistoricItem;
import org.openhab.core.persistence.PersistenceService;
import org.openhab.core.persistence.QueryablePersistenceService;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.openhab.io.caldav.CalDavEvent;
import org.openhab.io.caldav.CalDavLoader;
import org.openhab.io.caldav.CalDavQuery;
import org.openhab.io.caldav.EventUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This is a {@link PersistenceService} implementation using calDAV.
 *
 * @author Robert Delbrck
 * @since 1.8.0
 */
public class CaldavPersistenceService implements QueryablePersistenceService {

    private static final Logger logger = LoggerFactory.getLogger(CaldavPersistenceService.class);

    private static final String SERVICE_NAME = "caldav";

    private CalDavLoader calDavLoader;
    private ItemRegistry itemRegistry;

    @Override
    public String getName() {
        return SERVICE_NAME;
    }

    public void setCalDavLoader(CalDavLoader calDavLoader) {
        this.calDavLoader = calDavLoader;
    }

    public void unsetCalDavLoader() {
        this.calDavLoader = null;
    }

    public void activate() {
    }

    public void deactivate() {
    }

    public void setItemRegistry(ItemRegistry itemRegistry) {
        this.itemRegistry = itemRegistry;
    }

    public void unsetItemRegistry(ItemRegistry itemRegistry) {
        this.itemRegistry = null;
    }

    @Override
    public void store(Item item) {
        store(item, null);
    }

    private CaldavItem findLastOn(String alias, State state) {
        final FilterCriteria filter = new FilterCriteria();
        filter.setEndDate(new Date());
        filter.setItemName(alias);
        filter.setOrdering(FilterCriteria.Ordering.DESCENDING);
        filter.setPageSize(1);
        final Iterable<HistoricItem> query = this.query(filter);
        final Iterator<HistoricItem> iterator = query.iterator();

        if (iterator.hasNext()) {
            CaldavItem caldavItem = (CaldavItem) iterator.next();
            if (!isOff(caldavItem.getState())) {
                return caldavItem;
            }
        }
        return null;
    }

    @Override
    public void store(Item item, String alias) {
        if (item.getState() instanceof UnDefType) {
            return;
        }

        DateTime dateOffset = DateTime.now().plusDays(futureOffset);

        if (alias == null) {
            alias = item.getName();
        }
        State state = item.getState();
        logger.trace("persisting item: {}", item);

        if (!singleEvents) {
            // try to create events with correct ON OFF duration
            final CaldavItem lastOn = this.findLastOn(alias, state);
            if (lastOn != null) {
                if (isOff(item.getState())) {
                    CalDavEvent event = lastOn.getEvent();
                    event.setLastChanged(DateTime.now());
                    String offContent = EventUtils.createEnd(alias, state);
                    event.setContent(event.getContent() + "\n" + offContent);
                    event.setEnd(dateOffset);
                    logger.debug("existing event found, updated for persistence: {}", event);
                    this.calDavLoader.addEvent(event);
                } else {
                    CalDavEvent event = lastOn.getEvent();
                    event.setLastChanged(dateOffset);

                    String offContent = EventUtils.createBetween(alias, state);
                    event.setContent(event.getContent() + "\n" + offContent);
                    logger.debug("existing event found, updated for persistence: {}", event);
                    this.calDavLoader.addEvent(event);
                }
                return;
            }
        }

        logger.debug("creating new event");
        CalDavEvent event = new CalDavEvent();
        final String id = UUID.randomUUID().toString();
        event.setId(id);
        event.setName(alias);
        event.setLastChanged(DateTime.now());
        event.setContent(EventUtils.createBegin(alias, state));
        event.setStart(dateOffset);
        event.setEnd(dateOffset.plusMinutes(duration));
        event.setCalendarId(calendarId);
        event.setFilename("openHAB-" + id);
        logger.debug("new event for persistence created: {}", event);
        this.calDavLoader.addEvent(event);
    }

    private boolean isOff(State state) {
        if (state instanceof PercentType && state.equals(new PercentType(0))) {
            return true;
        } else if (state instanceof OnOffType && state.equals(OnOffType.OFF)) {
            return true;
        } else if (state instanceof OpenClosedType && state.equals(OpenClosedType.CLOSED)) {
            return true;
        }
        return false;
    }

    @Override
    public Iterable<HistoricItem> query(final FilterCriteria filter) {
        List<CalDavEvent> events = calDavLoader.getEvents(new CalDavQuery(calendarId));
        List<HistoricItem> outList = new ArrayList<HistoricItem>();

        for (CalDavEvent calDavEvent : events) {
            if (filter.getBeginDate() != null && calDavEvent.getEnd().toDate().before(filter.getBeginDate())) {
                continue;
            }
            if (filter.getEndDate() != null && calDavEvent.getStart().toDate().after(filter.getEndDate())) {
                continue;
            }

            Item item = null;
            try {
                item = this.itemRegistry.getItem(filter.getItemName());
            } catch (ItemNotFoundException e) {
                logger.error("item {} could not be found", filter.getItemName());
                continue;
            }

            final List<EventUtils.EventContent> parseContent = EventUtils.parseContent(calDavEvent, item);
            for (EventUtils.EventContent eventContent : parseContent) {
                if (filter.getBeginDate() != null
                        && eventContent.getTime().toDate().before(filter.getBeginDate())) {
                    continue;
                }
                if (filter.getEndDate() != null && eventContent.getTime().toDate().after(filter.getEndDate())) {
                    continue;
                }

                final State eventState = eventContent.getState();

                if (filter.getState() != null && filter.getOperator() != null) {
                    switch (filter.getOperator()) {
                    case EQ: {
                        if (!filter.getState().equals(eventState)) {
                            continue;
                        }
                        break;
                    }
                    case NEQ: {
                        if (filter.getState().equals(eventState)) {
                            continue;
                        }
                        break;
                    }
                    case LTE: {
                        if (eventState instanceof DecimalType && filter.getState() instanceof DecimalType) {
                            if (((DecimalType) eventState).longValue() > ((DecimalType) filter.getState())
                                    .longValue()) {
                                continue;
                            }
                        } else {
                            continue;
                        }
                        break;
                    }
                    case GTE: {
                        if (eventState instanceof DecimalType && filter.getState() instanceof DecimalType) {
                            if (((DecimalType) eventState).longValue() < ((DecimalType) filter.getState())
                                    .longValue()) {
                                continue;
                            }
                        } else {
                            continue;
                        }
                        break;
                    }
                    case LT: {
                        if (eventState instanceof DecimalType && filter.getState() instanceof DecimalType) {
                            if (((DecimalType) eventState).longValue() >= ((DecimalType) filter.getState())
                                    .longValue()) {
                                continue;
                            }
                        } else {
                            continue;
                        }
                        break;
                    }
                    case GT: {
                        if (eventState instanceof DecimalType && filter.getState() instanceof DecimalType) {
                            if (((DecimalType) eventState).longValue() <= ((DecimalType) filter.getState())
                                    .longValue()) {
                                continue;
                            }
                        } else {
                            continue;
                        }
                        break;
                    }
                    }
                }

                // just filtered events are here...
                final CaldavItem caldavItem = new CaldavItem(filter.getItemName(), eventState,
                        eventContent.getTime().toDate());
                caldavItem.setEvent(calDavEvent);
                outList.add(caldavItem);
            }
        }

        Collections.sort(outList, new Comparator<HistoricItem>() {
            @Override
            public int compare(HistoricItem arg0, HistoricItem arg1) {
                if (filter.getOrdering().equals(FilterCriteria.Ordering.ASCENDING)) {
                    return (int) (arg0.getTimestamp().getTime() - arg1.getTimestamp().getTime());
                } else {
                    return (int) (arg1.getTimestamp().getTime() - arg0.getTimestamp().getTime());
                }

            }
        });

        if (outList.size() < filter.getPageNumber() * filter.getPageSize()) {
            return Collections.emptyList();
        }

        outList = outList.subList(filter.getPageNumber() * filter.getPageSize(),
                Math.min((filter.getPageNumber() * filter.getPageSize()) + filter.getPageSize(), outList.size()));
        logger.trace("result size for query: {}", outList.size());

        return outList;
    }
}