/*
* Copyright 2014 Eric F. Savage, code@efsavage.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ajah.user.achievement;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import lombok.extern.java.Log;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import com.ajah.lang.ListMap;
import com.ajah.spring.jdbc.err.DataOperationException;
import com.ajah.user.UserId;
import com.ajah.user.achievement.data.AchievementManager;
import com.ajah.user.achievement.data.AchievementTagManager;
import com.ajah.user.achievement.data.AchievementUserManager;
import com.ajah.util.AjahUtils;
import com.ajah.util.StringUtils;
/**
* Determines and executes the propert {@link AchievementAnalyzer}s for a given
* user and tags.
*
* @author <a href="http://efsavage.com">Eric F. Savage</a>, <a
* href="mailto:code@efsavage.com">code@efsavage.com</a>.
*/
@Service
@Log
public class AchievementAnalyzerDispatcher implements ApplicationContextAware {
@Autowired
AchievementManager achievementManager;
@Autowired
AchievementTagManager achievementTagManager;
@Autowired
AchievementUserManager achievementUserManager;
ListMap<String, Achievement> tagCache = null;
private ApplicationContext applicationContext;
private synchronized void init() throws DataOperationException {
if (this.tagCache != null) {
return;
}
ListMap<String, Achievement> myTagCache = new ListMap<>();
List<Achievement> achievements = null;
while (achievements == null || achievements.size() == 100) {
achievements = this.achievementManager.list(null, AchievementStatus.ACTIVE, 0, 100);
for (Achievement achievement : achievements) {
log.fine(achievement.getName() + ": " + achievement.getAnalyzer());
if (StringUtils.isBlank(achievement.getAnalyzer())) {
log.warning("No analyzer for achievement " + achievement.getName());
continue;
}
try {
AchievementAnalyzer analyzer = (AchievementAnalyzer) this.applicationContext.getBean(Class.forName(achievement.getAnalyzer()));
achievement.setAchievementAnalyzer(analyzer);
List<AchievementTag> tags = this.achievementTagManager.list(achievement.getId());
for (AchievementTag tag : tags) {
myTagCache.putValue(tag.getName(), achievement);
}
} catch (BeansException | ClassNotFoundException e) {
log.log(Level.SEVERE, e.getMessage(), e);
}
}
}
this.tagCache = myTagCache;
}
/**
* Determines which {@link AchievementAnalyzer}s to run and executes them.
* If an analyzer matches more than one tag, it only executes once.
*
* @param userId
* The user to check for, required.
* @param tags
* The tags to match achievements on, required.
* @return true if the analyzers were successfully dispatched, otherwise
* false
* @throws DataOperationException
* If a query could not be executed.
*/
public boolean dispatch(UserId userId, String[] tags, AchievementDispatchListener listener) throws DataOperationException {
AjahUtils.requireParam(userId, "userId");
AjahUtils.requireParam(tags, "tags");
if (this.tagCache == null) {
init();
}
Set<Achievement> achievements = new HashSet<>();
for (String tag : tags) {
List<Achievement> list = this.tagCache.getList(tag);
if (list != null) {
achievements.addAll(list);
}
}
if (achievements.size() == 0) {
log.warning("No achievements matched " + StringUtils.join(",", tags));
return true;
}
for (Achievement achievement : achievements) {
AchievementUser achievementUser = this.achievementUserManager.find(userId, achievement.getId());
if (achievementUser != null && achievementUser.getStatus() == AchievementUserStatus.COMPLETED) {
log.fine("Already completed");
} else {
if(listener==null) {
achievement.getAchievementAnalyzer().analyze(userId, achievement, achievementUser);
} else {
listener.execute(userId, achievement, achievementUser);
}
}
}
return true;
}
/**
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}