001/**
002 * Copyright 2016 Tampere University of Technology, Pori Department
003 * 
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * 
008 *   http://www.apache.org/licenses/LICENSE-2.0
009 * 
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package service.tut.pori.apilta.alerts;
017
018import java.io.InputStream;
019import java.util.ArrayList;
020import java.util.Date;
021import java.util.List;
022import java.util.Set;
023
024import org.apache.commons.lang3.ArrayUtils;
025import org.apache.log4j.Logger;
026
027import core.tut.pori.context.ServiceInitializer;
028import core.tut.pori.http.parameters.DataGroups;
029import core.tut.pori.http.parameters.DateIntervalParameter.Interval;
030import core.tut.pori.http.parameters.Limits;
031import core.tut.pori.users.UserIdentity;
032import core.tut.pori.utils.ListUtils;
033import service.tut.pori.apilta.ApiltaProperties;
034import service.tut.pori.apilta.alerts.datatypes.Alert;
035import service.tut.pori.apilta.alerts.datatypes.AlertList;
036import service.tut.pori.apilta.alerts.datatypes.AlertUserIdentity.UserPermission;
037import service.tut.pori.apilta.alerts.datatypes.Location;
038import service.tut.pori.apilta.alerts.datatypes.LocationParameter;
039import service.tut.pori.apilta.files.FilesCore;
040import service.tut.pori.apilta.files.datatypes.FileDetails;
041import service.tut.pori.apilta.files.datatypes.FileDetailsList;
042
043/**
044 * 
045 * core methods for alerts service
046 */
047public final class AlertsCore {
048  private static final Logger LOGGER = Logger.getLogger(AlertsCore.class);
049  
050  /**
051   * 
052   */
053  private AlertsCore() {
054    // nothing needed
055  }
056
057  /**
058   * 
059   * @param alertGroupIdFilter
060   * @param alertTypeFilter
061   * @param authenticatedUser 
062   * @param createdFilter 
063   * @param dataGroups 
064   * @param limits
065   * @param location
066   * @param range
067   * @return list of alerts or null if none was found
068   */
069  public static AlertList retrieveAlerts(long[] alertGroupIdFilter, List<String> alertTypeFilter, UserIdentity authenticatedUser, Set<Interval> createdFilter, DataGroups dataGroups, Limits limits, Location location, Double range) {
070    if(!Location.isValid(location)){
071      if(ArrayUtils.isEmpty(alertGroupIdFilter)){
072        throw new IllegalArgumentException(LocationParameter.PARAMETER_DEFAULT_NAME+" or "+Definitions.PARAMETER_ALERT_GROUP_ID+" must be given.");
073      }else if(range != null){
074        throw new IllegalArgumentException(Definitions.PARAMETER_RANGE+" cannot be given without "+LocationParameter.PARAMETER_DEFAULT_NAME);
075      }
076    }else if(range == null){
077      LOGGER.debug("Using default range: "+Definitions.DEFAULT_RANGE);
078      range = Definitions.DEFAULT_RANGE;
079    }else if(range <= 0){
080      throw new IllegalArgumentException("Invalid range: "+range);
081    }
082    
083    List<Long> validGroupIds = ServiceInitializer.getDAOHandler().getDAO(AlertGroupsDAO.class).getAlertGroupIds(alertGroupIdFilter, UserPermission.READ_ALERTS, authenticatedUser);
084    if(validGroupIds == null){
085      LOGGER.debug("No valid alert groups for user, id: "+authenticatedUser.getUserId());
086      return null;
087    }
088    
089    AlertList alertList = ServiceInitializer.getDAOHandler().getDAO(AlertsDAO.class).getAlerts(validGroupIds, alertTypeFilter, createdFilter, dataGroups, limits, location, range);
090    if(!AlertList.isEmpty(alertList)){
091      for(Alert alert : alertList.getAlerts()){
092        FileDetailsList fileDetailsList = alert.getFiles();
093        if(!FileDetailsList.isEmpty(fileDetailsList)){ // alert has file details
094          List<FileDetails> GUIDList = fileDetailsList.getFiles(); // the basic list only contains GUIDs
095          ArrayList<FileDetails> resolved = new ArrayList<>(GUIDList.size());
096          for(FileDetails GUIDDetails : GUIDList){ // resolve file details
097            String guid = GUIDDetails.getGUID();
098            FileDetails resolvedDetails = FilesCore.getFileDetails(guid);
099            if(resolvedDetails == null){
100              LOGGER.warn("Could not resovle details for file, GUID: "+guid);
101            }else{
102              resolved.add(resolvedDetails);
103            }
104          }
105          fileDetailsList.setFiles((resolved.isEmpty() ? null : resolved)); // replace the original list
106        }
107      }
108    }
109    
110    return alertList;
111  }
112
113  /**
114   * 
115   * @param alert
116   * @param alertGroupIds 
117   * @param authenticatedUser
118   * @return identifier for the added alert or null on failure (permission denied)
119   * @throws IllegalArgumentException on bad input data
120   */
121  public static String addAlert(Alert alert, long[] alertGroupIds, UserIdentity authenticatedUser) throws IllegalArgumentException {
122    if(ArrayUtils.isEmpty(alertGroupIds)){
123      throw new IllegalArgumentException("Invalid or missing alert group ids.");
124    }
125    alert.setUserId(authenticatedUser); // make sure the authenticated user is the owner of this alert
126    if(!Alert.isValid(alert)){
127      throw new IllegalArgumentException("Invalid alert.");
128    }
129    
130    List<Long> validGroupIds = ServiceInitializer.getDAOHandler().getDAO(AlertGroupsDAO.class).getAlertGroupIds(alertGroupIds, UserPermission.POST_ALERT, authenticatedUser);
131    if(!ListUtils.containsAll(validGroupIds, alertGroupIds)){
132      LOGGER.warn("User, id: "+authenticatedUser.getUserId()+" attempted to post alert to invaliding alert group id.");
133      return null;
134    }
135    
136    Date created = alert.getCreated();
137    if(created == null){
138      LOGGER.debug("No created date, using current timestamp.");
139      created = new Date();
140      alert.setCreated(created);
141    }
142
143    if(alert.getValidUntil() == null){ //TODO check from database if a specific validity time is available for the alert, also, create the database tables
144      alert.setValidUntil(new Date(created.getTime()+ServiceInitializer.getPropertyHandler().getSystemProperties(ApiltaProperties.class).getAlertValidityTime()*60000));
145    }
146    
147    return ServiceInitializer.getDAOHandler().getDAO(AlertsDAO.class).addAlert(alert, validGroupIds); // use valid group ids list to remove possible duplicates in the id list  
148  }
149
150  /**
151   * 
152   * @param file
153   * @return details for the created file or null on failure (permission denied)
154   * @throws IllegalArgumentException on bad data
155   */
156  public static FileDetails createFile(InputStream file) throws IllegalArgumentException {
157    FileDetails details = FilesCore.createFile(file);
158    if(!FileDetails.isValid(details)){
159      throw new IllegalArgumentException("Failed to create file from the given data.");
160    }
161    
162    return details;
163  }
164  
165  //TODO "floating" rating system for alerts? possibility to confirm/reject an existing alert? (implement on web page? do not allow on the mobile app?)
166  // i.e. "alert feedback", also allow users to remove their own alerts directly?
167}