001/** 002 * Copyright 2010-2014 The Kuali Foundation 003 * 004 * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php 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 org.kuali.common.util.env; 017 018import static org.kuali.common.util.Annotations.extractClassAnnotation; 019 020import java.lang.reflect.Field; 021import java.util.ArrayList; 022import java.util.List; 023import java.util.Set; 024 025import org.kuali.common.util.ListUtils; 026import org.kuali.common.util.ReflectionUtils; 027import org.kuali.common.util.env.adapter.EnvAdapter; 028import org.kuali.common.util.env.annotation.Env; 029import org.kuali.common.util.env.annotation.EnvAdapterClass; 030import org.kuali.common.util.env.annotation.EnvIgnore; 031import org.kuali.common.util.env.annotation.EnvKeys; 032import org.kuali.common.util.spring.SpringUtils; 033import org.kuali.common.util.spring.env.BasicEnvironmentService; 034import org.kuali.common.util.spring.env.EnvironmentService; 035 036import com.google.common.base.Optional; 037import com.google.common.base.Preconditions; 038import com.google.common.collect.ImmutableList; 039 040public final class DefaultOverrideService implements OverrideService { 041 042 public EnvironmentService getEnv() { 043 return env; 044 } 045 046 public boolean isSkip() { 047 return skip; 048 } 049 050 private final EnvironmentService env; 051 private final boolean skip; 052 053 @Override 054 public void override(Object instance) { 055 Optional<Env> optional = extractClassAnnotation(instance.getClass(), Env.class); 056 if (!optional.isPresent()) { 057 return; 058 } 059 Env annotation = optional.get(); 060 if (annotation.skip()) { 061 return; 062 } 063 Optional<String> prefix = getPrefix(annotation); 064 Set<Field> fields = ReflectionUtils.getFields(instance.getClass(), annotation.includeInheritedFields()); 065 for (Field field : fields) { 066 override(prefix, instance, field); 067 } 068 } 069 070 private void override(Optional<String> prefix, Object instance, Field field) { 071 Optional<EnvIgnore> ignore = extractClassAnnotation(instance.getClass(), EnvIgnore.class); 072 if (ignore.isPresent()) { 073 return; 074 } 075 076 // Get the list of environment keys to look things up by 077 List<String> keys = getKeys(prefix, field); 078 079 // Extract the adapter annotation (if there is one) 080 Optional<EnvAdapterClass> adapterAnnotation = Optional.fromNullable(field.getAnnotation(EnvAdapterClass.class)); 081 082 // Extract the adapter itself (if there is one) 083 Optional<? extends EnvAdapter<?, ?>> adapter = getAdapter(adapterAnnotation); 084 085 // Target type in this context is the type we want the conversion service to convert the environment value into. 086 // The value that comes out of the environment is the "source" value for the conversion to the specific value on our 087 // domain model object 088 Class<?> targetType = adapter.isPresent() ? adapter.get().getSourceType() : field.getType(); 089 090 // Extract a value from the environment 091 Optional<?> value = SpringUtils.getOptionalProperty(env, keys, targetType); 092 093 // nothing to do if there is no value 094 if (!value.isPresent()) { 095 return; 096 } 097 098 // If there is an adapter, use it to convert the value we extracted from the environment into the value we need 099 if (adapter.isPresent()) { 100 Object result = ReflectionUtils.invokeMethod(adapter.get(), "convert", value.get()); 101 value = Optional.fromNullable(result); 102 } 103 104 // Store the value we have on the object 105 ReflectionUtils.set(instance, field, value.orNull()); 106 } 107 108 private Optional<? extends EnvAdapter<?, ?>> getAdapter(Optional<EnvAdapterClass> annotation) { 109 if (annotation.isPresent()) { 110 Class<? extends EnvAdapter<?, ?>> adapterClass = annotation.get().value(); 111 EnvAdapter<?, ?> adapter = ReflectionUtils.newInstance(adapterClass); 112 return Optional.of(adapter); 113 } else { 114 return Optional.absent(); 115 } 116 } 117 118 private List<String> getKeys(Optional<String> prefix, Field field) { 119 Optional<EnvKeys> optional = Optional.fromNullable(field.getAnnotation(EnvKeys.class)); 120 121 List<String> list = new ArrayList<String>(); 122 if (optional.isPresent() && optional.get().values().length > 0) { 123 list.addAll(ImmutableList.copyOf(optional.get().values())); 124 } else { 125 list.add(field.getName()); 126 } 127 if (prefix.isPresent()) { 128 return ListUtils.prefix(prefix.get(), ".", list); 129 } else { 130 return list; 131 } 132 } 133 134 private Optional<String> getPrefix(Env annotation) { 135 String prefix = annotation.prefix(); 136 if (Env.NOPREFIX.equals(prefix)) { 137 return Optional.absent(); 138 } else { 139 return Optional.of(prefix); 140 } 141 } 142 143 private DefaultOverrideService(Builder builder) { 144 this.env = builder.env; 145 this.skip = builder.skip; 146 } 147 148 public static class Builder { 149 150 private EnvironmentService env = new BasicEnvironmentService(); 151 private boolean skip = false; 152 153 public Builder withEnv(EnvironmentService env) { 154 this.env = env; 155 return this; 156 } 157 158 public Builder withSkip(boolean skip) { 159 this.skip = skip; 160 return this; 161 } 162 163 public DefaultOverrideService build() { 164 DefaultOverrideService instance = new DefaultOverrideService(this); 165 validate(instance); 166 return instance; 167 } 168 169 private void validate(DefaultOverrideService instance) { 170 Preconditions.checkNotNull(instance.env, "env may not be null"); 171 } 172 } 173 174}