/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.vulcan.wiring.osgi;
import com.liferay.vulcan.error.VulcanDeveloperError;
import com.liferay.vulcan.representor.ModelRepresentorMapper;
import com.liferay.vulcan.wiring.osgi.internal.GenericUtil;
import com.liferay.vulcan.wiring.osgi.internal.ModelRepresentorMapperTuple;
import com.liferay.vulcan.wiring.osgi.internal.RelatedModel;
import com.liferay.vulcan.wiring.osgi.internal.RepresentorBuilderImpl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.component.annotations.ReferencePolicyOption;
/**
* @author Alejandro Hernández
* @author Carlos Sierra Andrés
* @author Jorge Ferrer
*/
@Component(immediate = true, service = RepresentorManager.class)
public class RepresentorManager {
public RepresentorManager() {
Bundle bundle = FrameworkUtil.getBundle(RepresentorManager.class);
_bundleContext = bundle.getBundleContext();
}
public <T, V> List<RelatedModel<T, V>> getEmbeddedRelatedModels(
Class<T> modelClass) {
return (List)_embeddedRelatedModels.get(modelClass.getName());
}
public <T> Map<String, Function<T, Object>> getFieldFunctions(
Class<T> modelClass) {
return (Map)_fieldFunctions.get(modelClass.getName());
}
public <T> String getIdentifier(Class<T> modelClass, T model) {
Function<T, String> identifierFunction =
(Function<T, String>)_identifierFunctions.get(modelClass.getName());
return identifierFunction.apply(model);
}
public <T, V> List<RelatedModel<T, V>> getLinkedRelatedModels(
Class<T> modelClass) {
return (List)_linkedRelatedModels.get(modelClass.getName());
}
public <T> Map<String, String> getLinks(Class<T> modelClass) {
return _links.get(modelClass.getName());
}
public <T> Optional<ModelRepresentorMapper<T>>
getModelRepresentorMapperOptional(Class<T> modelClass) {
TreeSet<ModelRepresentorMapperTuple<?>> modelRepresentorMapperTuples =
_modelRepresentorMappers.get(modelClass.getName());
Optional<TreeSet<ModelRepresentorMapperTuple<?>>>
modelRepresentorMapperTuplesOptional = Optional.ofNullable(
modelRepresentorMapperTuples);
Optional<ModelRepresentorMapperTuple<?>>
firstModelRepresentorMapperTuple =
modelRepresentorMapperTuplesOptional.map(TreeSet::first);
return firstModelRepresentorMapperTuple.map(
modelRepresentorMapperTuple ->
(ModelRepresentorMapper<T>)modelRepresentorMapperTuple.
getModelRepresentorMapper());
}
public <T> List<String> getTypes(Class<T> modelClass) {
return _types.get(modelClass.getName());
}
@Reference(
cardinality = ReferenceCardinality.MULTIPLE,
policy = ReferencePolicy.DYNAMIC,
policyOption = ReferencePolicyOption.GREEDY
)
protected <T> void setServiceReference(
ServiceReference<ModelRepresentorMapper<T>> serviceReference) {
ModelRepresentorMapper<T> modelRepresentorMapper =
_bundleContext.getService(serviceReference);
Class<T> modelClass = _getModelClass(modelRepresentorMapper);
_addModelRepresentorMapper(
serviceReference, modelRepresentorMapper, modelClass);
_addModelClassMaps(modelClass);
}
protected <T> void unsetServiceReference(
ServiceReference<ModelRepresentorMapper<T>> serviceReference) {
ModelRepresentorMapper<T> modelRepresentorMapper =
_bundleContext.getService(serviceReference);
Class<T> modelClass = _getModelClass(modelRepresentorMapper);
_removeModelRepresentorMapper(modelRepresentorMapper, modelClass);
_removeModelClassMaps(modelClass);
Optional<ModelRepresentorMapper<T>> optional =
getModelRepresentorMapperOptional(modelClass);
optional.ifPresent(
firstModelRepresentorMapper -> _addModelClassMaps(modelClass));
}
private <T> void _addModelClassMaps(Class<T> modelClass) {
Optional<ModelRepresentorMapper<T>> optional =
getModelRepresentorMapperOptional(modelClass);
Map<String, Function<?, Object>> fieldFunctions = new HashMap<>();
_fieldFunctions.put(modelClass.getName(), fieldFunctions);
List<RelatedModel<?, ?>> embeddedRelatedModels = new ArrayList<>();
_embeddedRelatedModels.put(modelClass.getName(), embeddedRelatedModels);
List<RelatedModel<?, ?>> linkedRelatedModels = new ArrayList<>();
_linkedRelatedModels.put(modelClass.getName(), linkedRelatedModels);
Map<String, String> links = new HashMap<>();
_links.put(modelClass.getName(), links);
List<String> types = new ArrayList<>();
_types.put(modelClass.getName(), types);
optional.ifPresent(
modelRepresentorMapper -> modelRepresentorMapper.buildRepresentor(
new RepresentorBuilderImpl<>(
modelClass, _identifierFunctions, fieldFunctions,
embeddedRelatedModels, linkedRelatedModels, links, types)));
}
private <T> void _addModelRepresentorMapper(
ServiceReference<ModelRepresentorMapper<T>> serviceReference,
ModelRepresentorMapper<T> modelRepresentorMapper, Class<T> modelClass) {
_modelRepresentorMappers.computeIfAbsent(
modelClass.getName(), name -> new TreeSet<>());
ModelRepresentorMapperTuple<T> modelRepresentorMapperTuple =
new ModelRepresentorMapperTuple<>(
serviceReference, modelRepresentorMapper);
TreeSet<ModelRepresentorMapperTuple<?>> modelRepresentorMapperTuples =
_modelRepresentorMappers.get(modelClass.getName());
modelRepresentorMapperTuples.add(modelRepresentorMapperTuple);
}
private <T> Class<T> _getModelClass(
ModelRepresentorMapper<T> modelRepresentorMapper) {
Optional<Class<T>> optional = GenericUtil.getGenericClassOptional(
modelRepresentorMapper, ModelRepresentorMapper.class);
return optional.orElseThrow(
() -> new VulcanDeveloperError.MustHaveValidGenericType(
modelRepresentorMapper.getClass()));
}
private <T> void _removeModelClassMaps(Class<T> modelClass) {
_embeddedRelatedModels.remove(modelClass.getName());
_fieldFunctions.remove(modelClass.getName());
_identifierFunctions.remove(modelClass.getName());
_linkedRelatedModels.remove(modelClass.getName());
_links.remove(modelClass.getName());
_types.remove(modelClass.getName());
}
private <T> void _removeModelRepresentorMapper(
ModelRepresentorMapper modelRepresentorMapper, Class<T> modelClass) {
TreeSet<ModelRepresentorMapperTuple<?>> modelRepresentorMapperTuples =
_modelRepresentorMappers.get(modelClass.getName());
modelRepresentorMapperTuples.removeIf(
modelRepresentorMapperTuple -> {
if (modelRepresentorMapperTuple.getModelRepresentorMapper() ==
modelRepresentorMapper) {
return true;
}
return false;
});
}
private final BundleContext _bundleContext;
private final Map<String, List<RelatedModel<?, ?>>> _embeddedRelatedModels =
new ConcurrentHashMap<>();
private final Map<String, Map<String, Function<?, Object>>>
_fieldFunctions = new ConcurrentHashMap<>();
private final Map<String, Function<?, String>> _identifierFunctions =
new ConcurrentHashMap<>();
private final Map<String, List<RelatedModel<?, ?>>> _linkedRelatedModels =
new ConcurrentHashMap<>();
private final Map<String, Map<String, String>> _links =
new ConcurrentHashMap<>();
private final Map<String, TreeSet<ModelRepresentorMapperTuple<?>>>
_modelRepresentorMappers = new ConcurrentHashMap<>();
private final Map<String, List<String>> _types = new ConcurrentHashMap<>();
}