All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.atteo.moonshine.services.internal.ServiceModuleRewriter Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2013 Atteo.
 *
 * 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 org.atteo.moonshine.services.internal;

import java.lang.annotation.Annotation;
import java.util.List;

import org.atteo.moonshine.services.ImportService;
import org.atteo.moonshine.services.Service;

import com.google.common.base.Strings;
import com.google.inject.Binder;
import com.google.inject.Binding;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.PrivateBinder;
import com.google.inject.name.Names;
import com.google.inject.spi.DefaultElementVisitor;
import com.google.inject.spi.Element;
import com.google.inject.spi.Elements;
import com.google.inject.spi.InjectionRequest;
import com.google.inject.spi.PrivateElements;

public class ServiceModuleRewriter {
	/**
	 * Annotate exposed bindings with Names.named(service.getId()).
	 * Additionally request injection of service object.
	 */
	public static List annotateExposedWithId(final List elements, final Service service) {
		final boolean singleton = ReflectionTools.isSingleton(service.getClass());
		return Elements.getElements(new Module() {
			@Override
			public void configure(final Binder binder) {
				final PrivateBinder privateBinder = binder.newPrivateBinder();
				privateBinder.requestInjection(service);

				for (Element element : elements) {
					element.acceptVisitor(new DefaultElementVisitor() {
						@Override
						public Void visit(PrivateElements privateElements) {
							annotateExposedWithId(privateBinder, privateElements, service);
							return null;
						}

						@Override
						public  Void visit(Binding binding) {
							binding.applyTo(privateBinder);
							Key oldKey = binding.getKey();
							if (!singleton && !Strings.isNullOrEmpty(service.getId())) {
								bindKey(privateBinder, oldKey, Names.named(service.getId()));
							} else {
								privateBinder.expose(oldKey);
							}
							return null;
						}

						@Override
						protected Void visitOther(Element element) {
							element.applyTo(binder);
							return null;
						}
					});
				}
			}
		});
	}

	private static  void bindKey(PrivateBinder binder, Key oldKey, Annotation annotation) {
		Key newKey = Key.get(oldKey.getTypeLiteral(), annotation);
		binder.bind(newKey).to(oldKey);
		binder.expose(newKey);
	}

	private static void annotateExposedWithId(final PrivateBinder binder,
			final PrivateElements elements, final Service service) {

		final boolean singleton = ReflectionTools.isSingleton(service.getClass());

		// rewrite all bindings
		for (Element element : elements.getElements()) {
			element.applyTo(binder);
		}

		// rewrite all exposed bindings to include id
		for (Key oldKey : elements.getExposedKeys()) {
			if (!singleton && !Strings.isNullOrEmpty(service.getId())) {
				bindKey(binder, oldKey, Names.named(service.getId()));
			} else {
				binder.expose(oldKey);
			}
		}
	}

	/**
	 * Create a module with all provided elements and also with bindings imported
	 * with {@link ImportService} annotation.
	 * @param service service to scan for {@link ImportService} annotation
	 * @param services list of all services
	 * @param hints list where hints will be stored
	 * @return provided elements with bindings imported from given service
	 */
	public static List importBindings(final ServiceWrapper service,
			final List services, final List hints) {
		return Elements.getElements(new Module() {
			@Override
			public void configure(final Binder binder) {
				final PrivateBinder privateBinder = binder.newPrivateBinder();
				for (Element element : service.getElements()) {
					element.acceptVisitor(new DefaultElementVisitor() {
						@Override
						public Void visit(PrivateElements privateElements) {
							importBindings(privateBinder, privateElements, service, services, hints);
							return null;
						}

						@Override
						public Void visit(InjectionRequest injectionRequest) {
							injectionRequest.applyTo(privateBinder);
							return null;
						}

						@Override
						protected Void visitOther(Element element) {
							// copy all elements
							element.applyTo(binder);
							return null;
						}
					});
				}
			}
		});
	}

	private static void importBindings(final PrivateBinder binder, PrivateElements elements, ServiceWrapper service,
			List services, List hints) {

		// copy all elements
		for (Element element : elements.getElements()) {
			element.applyTo(binder);
		}
		for (Key key : elements.getExposedKeys()) {
			binder.expose(key);
		}

		for (final ServiceWrapper.Dependency dependency : service.getDependencies()) {
			List importedElements;

			importedElements = dependency.getService().getElements();
			if (importedElements == null) {
				throw new RuntimeException("Imported service does not specify any module");
			}

			for (final Element element : importedElements) {
				element.acceptVisitor(new DefaultElementVisitor() {
					private  void bindKey(Key key) {
						Key sourceKey;

						Class annotation = dependency.getAnnotation();
						if (annotation == ImportService.NoAnnotation.class) {
							sourceKey = Key.get(key.getTypeLiteral());
						} else {
							sourceKey = Key.get(key.getTypeLiteral(), annotation);
						}

						if (!sourceKey.equals(key)) {
							binder.withSource(element.getSource()).bind(sourceKey).to(key);
						}
					}

					@Override
					public Void visit(PrivateElements privateElements) {
						for (Key key : privateElements.getExposedKeys()) {
							bindKey(key);
						}
						return null;
					}

					@Override
					public  Void visit(Binding binding) {
						bindKey(binding.getKey());
						return null;
					}
				});
			}
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy