package net.unicon.cas.addons.serviceregistry;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.apache.commons.io.IOUtils;
import org.jasig.cas.services.AbstractRegisteredService;
import org.jasig.cas.services.RegisteredService;
import org.springframework.core.io.Resource;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
/**
* An extension of the JsonServiceRegistryDao that is able to support both read/write operations when
* saving or deleting registered services.
* <p/>
* Note: This implementation is NOT transactional nor is it thread-safe. No such implementation can be possible on top
* of an ordinary file system.
*
* @author Misagh Moayyed
* @author Unicon, inc.
* @since 1.6
*/
public final class ReadWriteJsonServiceRegistryDao extends JsonServiceRegistryDao {
public ReadWriteJsonServiceRegistryDao(final Resource servicesConfigFile) {
super(servicesConfigFile);
this.objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
}
@Override
protected RegisteredService saveInternal(final RegisteredService registeredService) {
logger.debug("Loading service definitions from resource [{}]", this.servicesConfigFile.getFilename());
final List<RegisteredService> resolvedServices = super.loadServices();
final List<RegisteredService> col = new ArrayList<RegisteredService>(resolvedServices);
if (registeredService.getId() < 0) {
if (registeredService instanceof AbstractRegisteredService) {
final Random random = new Random(registeredService.hashCode());
final int serviceId = random.nextInt(Integer.MAX_VALUE);
((AbstractRegisteredService) registeredService).setId(serviceId);
}
}
boolean foundAndRemovedService = false;
final Iterator<RegisteredService> it = col.iterator();
while(!foundAndRemovedService && it.hasNext()) {
if (it.next().getId() == registeredService.getId()) {
it.remove();
foundAndRemovedService = true;
}
}
col.add(registeredService);
saveListOfRegisteredServices(col);
return registeredService;
}
@Override
protected boolean deleteInternal(final RegisteredService registeredService) {
logger.debug("Loading service definitions from resource [{}]", this.servicesConfigFile.getFilename());
final List<RegisteredService> resolvedServices = super.loadServices();
final RegisteredService regServiceToDelete = findServiceById(registeredService.getId());
if (regServiceToDelete != null) {
logger.debug("Found service definition to remove: [{}]", regServiceToDelete);
final List<RegisteredService> col = new ArrayList<RegisteredService>(resolvedServices);
col.remove(regServiceToDelete);
saveListOfRegisteredServices(col);
return true;
}
return false;
}
private void saveListOfRegisteredServices(final List<RegisteredService> col) {
OutputStream out = null;
FileOutputStream fout = null;
try {
fout = new FileOutputStream(this.servicesConfigFile.getFile());
out = new BufferedOutputStream(fout);
final Map<String, Object> map = new LinkedHashMap<String, Object>(col.size());
map.put(SERVICES_KEY, col);
logger.debug("Writing [{}] service definitions to resource [{}]", col.size(), this.servicesConfigFile.getFilename());
this.objectMapper.writerWithDefaultPrettyPrinter().writeValue(out, map);
fout.flush();
out.flush();
} catch (final Exception e) {
logger.error(e.getMessage(), e);
} finally {
IOUtils.closeQuietly(fout);
IOUtils.closeQuietly(out);
}
}
}