package org.apereo.cas.ticket.registry.support.kryo.serial; import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.Serializer; import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; import com.google.common.base.Throwables; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.ObjectUtils; import org.apereo.cas.services.AbstractRegisteredService; import org.apereo.cas.services.DefaultRegisteredServiceAccessStrategy; import org.apereo.cas.services.DefaultRegisteredServiceUsernameProvider; import org.apereo.cas.services.LogoutType; import org.apereo.cas.services.RefuseRegisteredServiceProxyPolicy; import org.apereo.cas.services.RegexRegisteredService; import org.apereo.cas.services.RegisteredService; import org.apereo.cas.services.RegisteredServicePublicKeyImpl; import org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy; import java.net.URL; import java.util.HashSet; /** * Serializer for {@link RegisteredService} instances. * @author Misagh Moayyed * @since 4.1.0 */ public class RegisteredServiceSerializer extends Serializer<RegisteredService> { /** * In case the url object is null in the service, * we need to be able to return a default/mock url. * @return mock url */ private static URL getEmptyUrl() { try { return new URL("https://"); } catch (final Exception e) { throw Throwables.propagate(e); } } @Override public void write(final Kryo kryo, final Output output, final RegisteredService service) { kryo.writeObject(output, service.getServiceId()); kryo.writeObject(output, StringUtils.defaultIfEmpty(service.getName(), StringUtils.EMPTY)); kryo.writeObject(output, StringUtils.defaultIfEmpty(service.getDescription(), StringUtils.EMPTY)); kryo.writeObject(output, service.getId()); kryo.writeObject(output, service.getEvaluationOrder()); kryo.writeObject(output, ObjectUtils.defaultIfNull(service.getLogo(), getEmptyUrl())); kryo.writeObject(output, service.getLogoutType()); kryo.writeObject(output, ObjectUtils.defaultIfNull(service.getLogoutUrl(), getEmptyUrl())); kryo.writeObject(output, new HashSet<>(service.getRequiredHandlers())); kryo.writeObject(output, StringUtils.defaultIfEmpty(service.getTheme(), StringUtils.EMPTY)); writeObjectByReflection(kryo, output, ObjectUtils.defaultIfNull(service.getPublicKey(), new RegisteredServicePublicKeyImpl())); writeObjectByReflection(kryo, output, ObjectUtils.defaultIfNull(service.getProxyPolicy(), new RefuseRegisteredServiceProxyPolicy())); writeObjectByReflection(kryo, output, ObjectUtils.defaultIfNull(service.getAttributeReleasePolicy(), new ReturnAllowedAttributeReleasePolicy())); writeObjectByReflection(kryo, output, ObjectUtils.defaultIfNull(service.getUsernameAttributeProvider(), new DefaultRegisteredServiceUsernameProvider())); writeObjectByReflection(kryo, output, ObjectUtils.defaultIfNull(service.getAccessStrategy(), new DefaultRegisteredServiceAccessStrategy())); } @Override public RegisteredService read(final Kryo kryo, final Input input, final Class<RegisteredService> type) { final AbstractRegisteredService svc = new RegexRegisteredService(); svc.setServiceId(kryo.readObject(input, String.class)); svc.setName(kryo.readObject(input, String.class)); svc.setDescription(kryo.readObject(input, String.class)); svc.setId(kryo.readObject(input, Long.class)); svc.setEvaluationOrder(kryo.readObject(input, Integer.class)); svc.setLogo(kryo.readObject(input, URL.class)); svc.setLogoutType(kryo.readObject(input, LogoutType.class)); svc.setLogoutUrl(kryo.readObject(input, URL.class)); svc.setRequiredHandlers(kryo.readObject(input, HashSet.class)); svc.setTheme(kryo.readObject(input, String.class)); svc.setPublicKey(readObjectByReflection(kryo, input)); svc.setProxyPolicy(readObjectByReflection(kryo, input)); svc.setAttributeReleasePolicy(readObjectByReflection(kryo, input)); svc.setUsernameAttributeProvider(readObjectByReflection(kryo, input)); svc.setAccessStrategy(readObjectByReflection(kryo, input)); return svc; } /** * Write object by reflection. * * @param kryo the kryo * @param output the output * @param obj the obj */ private static void writeObjectByReflection(final Kryo kryo, final Output output, final Object obj) { final String className = obj.getClass().getCanonicalName(); kryo.writeObject(output, className); kryo.writeObject(output, obj); } /** * Read object by reflection. * * @param <T> the type parameter * @param kryo the kryo * @param input the input * @return the t */ private static <T> T readObjectByReflection(final Kryo kryo, final Input input) { try { final String className = kryo.readObject(input, String.class); final Class<T> clazz = (Class<T>) Class.forName(className); return kryo.readObject(input, clazz); } catch (final Exception e) { throw Throwables.propagate(e); } } }