/** * 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.io.caldav; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat; import org.openhab.core.items.Item; import org.openhab.core.items.ItemNotFoundException; import org.openhab.core.items.ItemRegistry; import org.openhab.core.types.Command; import org.openhab.core.types.State; import org.openhab.core.types.TypeParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class EventUtils { private static final Logger log = LoggerFactory.getLogger(EventUtils.class); // patterns used to parse event entries private static final Pattern COMMAND_PATTERN = Pattern.compile("(?:BEGIN|END|BETWEEN):"); private static final Pattern LINE_PATTERN = Pattern.compile("(BEGIN|END|BETWEEN)(:[^:\\s]{19})?:([^:\\s]+):(.+)"); public static final String SCOPE_BEGIN = "BEGIN"; public static final String SCOPE_END = "END"; public static final String SCOPE_BETWEEN = "BETWEEN"; public static final String DATE_FORMAT = "dd.MM.yyyy'T'HH:mm:ss"; public static final String SEPERATOR = ":"; public static List<EventContent> parseContent(CalDavEvent event, ItemRegistry itemRegistry, String scope, String defaultItemOnBegin) { return parseContent(event, itemRegistry, null, scope, defaultItemOnBegin); } public static List<EventContent> parseContent(CalDavEvent event, ItemRegistry itemRegistry, String scope) { return parseContent(event, itemRegistry, null, scope, null); } public static List<EventContent> parseContent(CalDavEvent event, Item item) { return parseContent(event, null, item, null, null); } private static List<EventContent> parseContent(CalDavEvent event, ItemRegistry itemRegistry, Item itemIn, String expectedScope, String defaultItemOnBegin) { final List<EventContent> outMap = new ArrayList<EventUtils.EventContent>(); // no content, nothing to parse if (StringUtils.isEmpty(event.getContent())) { return outMap; } try { final BufferedReader reader = new BufferedReader(new StringReader(event.getContent())); String line = null; while ((line = reader.readLine()) != null) { Item item = itemIn; final EventLine eventLine = parseEventLine(line.trim(), event, defaultItemOnBegin); if (eventLine == null) { continue; } if (expectedScope != null && !expectedScope.equals(eventLine.scope)) { continue; } if (item == null) { if (itemRegistry == null) { log.error("item is null, but itemRegistry as well"); continue; } try { item = itemRegistry.getItem(eventLine.itemName); } catch (ItemNotFoundException e) { log.error("cannot find item: {}", eventLine.itemName); continue; } } if (!item.getName().equals(eventLine.itemName)) { log.trace("name of item {} does not match itemName {}", item.getName(), eventLine.itemName); continue; } final State state = TypeParser.parseState(item.getAcceptedDataTypes(), eventLine.stateString); final Command command = TypeParser.parseCommand(item.getAcceptedCommandTypes(), eventLine.stateString); log.trace("add item {} to action list (scope={}, state={}, time={})", item, eventLine.scope, state, eventLine.time); outMap.add(new EventContent(eventLine.scope, item, state, command, eventLine.time)); } } catch (IOException e) { log.error("cannot parse event content", e); } return outMap; } private static EventLine parseEventLine(String line, CalDavEvent event, String defaultItemOnBegin) { final Matcher matcher = LINE_PATTERN.matcher(line); if (matcher.matches()) { final String scope = matcher.group(1); final String itemName = matcher.group(3); final String stateString = matcher.group(4); if (itemName.trim().length() > 0 && stateString.trim().length() > 0) { if (SCOPE_BEGIN.equals(scope)) { return new EventLine(itemName, stateString, scope, event.getStart()); } if (SCOPE_END.equals(scope)) { return new EventLine(itemName, stateString, scope, event.getEnd()); } if (SCOPE_BETWEEN.equals(scope)) { final String timeString = matcher.group(2); final DateTime time = DateTimeFormat.forPattern(EventUtils.DATE_FORMAT).parseDateTime(timeString); return new EventLine(itemName, stateString, scope, time); } } } else if (defaultItemOnBegin != null && !COMMAND_PATTERN.matcher(line).matches()) { // if defaultItemOnBegin is set, use entire line as command value return new EventLine(defaultItemOnBegin, line, SCOPE_BEGIN, event.getStart()); } log.error("invalid format for line: {}", line); return null; // nothing meaningful found in line } private EventUtils() { } private final static class EventLine { final String itemName; final String stateString; final String scope; final DateTime time; EventLine(String itemName, String stateString, String scope, DateTime time) { this.itemName = itemName; this.stateString = stateString; this.scope = scope; this.time = time; } } public final static class EventContent { private final Item item; private final State state; private final Command command; private final DateTime time; private final String scope; public EventContent(String scope, Item item, State state, Command command, DateTime time) { this.scope = scope; this.item = item; this.state = state; this.command = command; this.time = time; } public Item getItem() { return item; } public State getState() { return state; } public Command getCommand() { return command; } public DateTime getTime() { return time; } public String getScope() { return scope; } @Override public String toString() { return "EventContent [item=" + item + ", state=" + state + ", command=" + command + ", time=" + time + ", scope=" + scope + "]"; } } public static String createBetween(String itemName, State state) { return new StringBuilder().append(SCOPE_BETWEEN).append(SEPERATOR) .append(DateTimeFormat.forPattern(EventUtils.DATE_FORMAT).print(DateTime.now())).append(SEPERATOR) .append(itemName).append(SEPERATOR).append(state).toString(); } public static String createEnd(String alias, State state) { return new StringBuilder().append(SCOPE_END).append(SEPERATOR).append(alias).append(SEPERATOR).append(state) .toString(); } public static String createBegin(String alias, State state) { return new StringBuilder().append(SCOPE_BEGIN).append(SEPERATOR).append(alias).append(SEPERATOR).append(state) .toString(); } }