Skip to content

Commit

Permalink
making things thread safe for #77
Browse files Browse the repository at this point in the history
  • Loading branch information
elucash committed Jan 21, 2015
1 parent 79378a1 commit ed890ce
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 39 deletions.
Expand Up @@ -16,13 +16,15 @@
package org.immutables.generator;

import com.google.common.base.Predicate;
import com.google.common.collect.Maps;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.lang.model.element.TypeElement;

public final class ClasspathAvailability {
// static non-thread-safe cache? ok!
private static final Map<String, Boolean> availableClasses = Maps.newHashMap();
private static final Map<String, Boolean> availableClasses =
Collections.synchronizedMap(new HashMap<String, Boolean>());

public final Predicate<String> available = new Predicate<String>() {
@Override
Expand Down
83 changes: 52 additions & 31 deletions generator/src/org/immutables/generator/StaticEnvironment.java
Expand Up @@ -26,23 +26,62 @@
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.TypeElement;

/**
* This design is flawed and should be removed. Last time it was not done "right"
* because of lack of some form of dependency injection in generators and infrastructure.
*/
final class StaticEnvironment {
private StaticEnvironment() {}

private static ClassToInstanceMap<Completable> components;
private static ProcessingEnvironment processing;
private static RoundEnvironment round;
private static Set<TypeElement> annotations;
private static boolean initialized;
private static class EnvironmentState {
private ClassToInstanceMap<Completable> components;
private ProcessingEnvironment processing;
private RoundEnvironment round;
private Set<TypeElement> annotations;
private boolean initialized;

void shutdown() {
for (Completable component : components.values()) {
component.complete();
}
components = null;
processing = null;
round = null;
annotations = null;
initialized = false;

state.remove();
}

void init(Set<? extends TypeElement> annotations, RoundEnvironment round, ProcessingEnvironment processing) {
this.components = MutableClassToInstanceMap.create();
this.processing = processing;
this.round = round;
this.annotations = ImmutableSet.copyOf(annotations);
this.initialized = true;
}
}

private static final ThreadLocal<EnvironmentState> state = new ThreadLocal<EnvironmentState>() {
@Override
protected EnvironmentState initialValue() {
return new EnvironmentState();
}
};

private static EnvironmentState state() {
EnvironmentState s = state.get();
Preconditions.checkState(s.initialized, "Static environment should be initialized");
return s;
}

interface Completable {
void complete();
}

static <T extends Completable> T getInstance(Class<T> type, Supplier<T> supplier) {
checkInitialized();
@Nullable
T instance = components.getInstance(type);
ClassToInstanceMap<Completable> components = state().components;
@Nullable T instance = components.getInstance(type);
if (instance == null) {
instance = supplier.get();
components.putInstance(type, instance);
Expand All @@ -51,44 +90,26 @@ static <T extends Completable> T getInstance(Class<T> type, Supplier<T> supplier
}

static ProcessingEnvironment processing() {
checkInitialized();
return processing;
return state().processing;
}

static RoundEnvironment round() {
checkInitialized();
return round;
return state().round;
}

static Set<TypeElement> annotations() {
checkInitialized();
return annotations;
}

private static void checkInitialized() {
Preconditions.checkState(initialized, "Static environment should be initialized");
return state().annotations;
}

static void shutdown() throws Exception {
for (Completable component : components.values()) {
component.complete();
}
components = null;
processing = null;
round = null;
annotations = null;
initialized = false;
state().shutdown();
}

static void init(
Set<? extends TypeElement> annotations,
RoundEnvironment round,
ProcessingEnvironment processing) {
StaticEnvironment.components = MutableClassToInstanceMap.create();
StaticEnvironment.processing = processing;
StaticEnvironment.round = round;
StaticEnvironment.annotations = ImmutableSet.copyOf(annotations);
StaticEnvironment.initialized = true;
state.get().init(annotations, round, processing);
}

}
Expand Up @@ -15,6 +15,7 @@
*/
package org.immutables.value.processor.meta;

import javax.annotation.concurrent.GuardedBy;
import com.google.common.base.CaseFormat;
import com.google.common.collect.Maps;
import java.util.Map;
Expand All @@ -23,7 +24,7 @@
import org.immutables.value.Value.Style;

public final class Styles {
// Let it be static non-thread-safe cache, it's ok for now
@GuardedBy("cache")
private static final Map<Style, Styles> cache = Maps.newHashMap();

@Style
Expand All @@ -36,12 +37,14 @@ public static Style defaultStyle() {
}

public static Styles using(Style style) {
Styles namings = cache.get(style);
if (namings == null) {
namings = new Styles(style);
cache.put(style, namings);
synchronized (cache) {
Styles namings = cache.get(style);
if (namings == null) {
namings = new Styles(style);
cache.put(style, namings);
}
return namings;
}
return namings;
}

private final Style style;
Expand Down

0 comments on commit ed890ce

Please sign in to comment.