Project

General

Profile

1
package eu.dnetlib.enabling.locators;
2

    
3
import java.io.StringReader;
4
import java.io.StringWriter;
5
import java.util.*;
6
import java.util.stream.Collectors;
7

    
8
import eu.dnetlib.enabling.tools.BaseServiceUtils;
9
import eu.dnetlib.rmi.common.BaseService;
10
import eu.dnetlib.rmi.enabling.ISLookUpException;
11
import eu.dnetlib.rmi.enabling.ISLookUpService;
12
import eu.dnetlib.soap.cxf.StandaloneCxfEndpointReferenceBuilder;
13
import org.apache.commons.lang3.StringUtils;
14
import org.apache.commons.lang3.math.NumberUtils;
15
import org.apache.commons.logging.Log;
16
import org.apache.commons.logging.LogFactory;
17
import org.dom4j.Document;
18
import org.dom4j.DocumentException;
19
import org.dom4j.Element;
20
import org.dom4j.io.SAXReader;
21
import org.springframework.beans.BeansException;
22
import org.springframework.beans.factory.annotation.Autowired;
23
import org.springframework.beans.factory.annotation.Required;
24
import org.springframework.context.ApplicationContext;
25
import org.springframework.context.ApplicationContextAware;
26

    
27
public class DefaultUniqueServiceLocator implements UniqueServiceLocator, ApplicationContextAware {
28

    
29
	/**
30
	 * logger.
31
	 */
32
	private static final Log log = LogFactory.getLog(DefaultUniqueServiceLocator.class);
33
	/**
34
	 * XML Parser
35
	 */
36
	private final SAXReader reader = new SAXReader();
37
	// PreferLocalRunningInstanceComparator();
38
	private ApplicationContext appContext;
39
	private Comparator<ServiceRunningInstance> defaultComparator; // = new
40
	/**
41
	 * An instance of isLookupService (local or stub)
42
	 */
43
	@Autowired
44
	private ISLookUpService isLookupService;
45
	/**
46
	 * build epr.
47
	 */
48
	@Autowired
49
	private StandaloneCxfEndpointReferenceBuilder eprBuilder;
50

    
51
	@Override
52
	public <T extends BaseService> T getService(final Class<T> clazz) {
53
		return getService(clazz, true);
54
	}
55

    
56
	@Override
57
	public <T extends BaseService> T getService(final Class<T> clazz, final Comparator<ServiceRunningInstance> comparator) {
58
		final String serviceName = BaseServiceUtils.getServiceName(clazz);
59
		return findRunningInstances(serviceName, comparator).get(0).obtainClient(clazz, this.eprBuilder);
60
	}
61

    
62
	@Override
63
	public <T extends BaseService> T getService(final Class<T> clazz, final String profileId) {
64
		final String profile = obtainServiceProfile(profileId);
65

    
66
		try {
67
			return obtainRunningInstance(profile, obtainLocalServices()).obtainClient(clazz, this.eprBuilder);
68
		} catch (final Exception e) {
69
			log.error("cannot instantiate service from id: " + profileId, e);
70
			throw new IllegalStateException("cannot instantiate service from id: " + profileId, e);
71
		}
72
	}
73

    
74
	@Override
75
	public <T extends BaseService> T getService(final Class<T> clazz, final boolean local) {
76
		if (clazz.isInstance(this.isLookupService)) { return clazz.cast(this.isLookupService); }
77

    
78
		if (local) {
79
			try {
80
				final Map<String, T> beans = this.appContext.getBeansOfType(clazz);
81
				if ((beans != null) && !beans.isEmpty()) { return beans.values().iterator().next(); }
82
			} catch (final Throwable e) {
83
				log.warn("No beans found in context, class " + clazz);
84
			}
85
		}
86

    
87
		return getService(clazz, this.defaultComparator);
88
	}
89

    
90
	@Override
91
	public <T extends BaseService> String getServiceId(final Class<T> clazz) {
92
		return getServiceId(clazz, this.defaultComparator);
93
	}
94

    
95
	@Override
96
	public <T extends BaseService> String getServiceId(final Class<T> clazz, final Comparator<ServiceRunningInstance> comparator) {
97
		return findRunningInstances(BaseServiceUtils.getServiceName(clazz), comparator).get(0).getServiceId();
98
	}
99

    
100
	@Override
101
	public <T extends BaseService> String getServiceId(final Class<T> clazz, final String profileId) {
102
		final String profile = obtainServiceProfile(profileId);
103
		final ServiceRunningInstance instance = obtainRunningInstance(profile, obtainLocalServices());
104
		return instance.getServiceId();
105
	}
106

    
107
	@Override
108
	public <T extends BaseService> Set<T> getAllServices(final Class<T> clazz) {
109
		final Set<T> res = new HashSet<>();
110
		for (final ServiceRunningInstance instance : findRunningInstances(BaseServiceUtils.getServiceName(clazz), null)) {
111
			res.add(instance.obtainClient(clazz, this.eprBuilder));
112
		}
113
		return res;
114
	}
115

    
116
	@Override
117
	public <T extends BaseService> Set<String> getAllServiceIds(final Class<T> clazz) {
118
		return
119
				findRunningInstances(BaseServiceUtils.getServiceName(clazz), null)
120
						.stream()
121
						.map(ServiceRunningInstance::getServiceId)
122
						.collect(Collectors.toSet());
123

    
124
	}
125

    
126
	private synchronized ServiceRunningInstance obtainRunningInstance(final String profile, final Map<String, BaseService> locals) {
127
		try {
128
			final Document doc = this.reader.read(new StringReader(profile));
129
			final String url = doc.valueOf("//PROTOCOL[@name = 'SOAP']/@address");
130
			final String id = doc.valueOf("//RESOURCE_IDENTIFIER/@value");
131
			final Map<String, String> props = new HashMap<>();
132
			final BaseService local = locals.containsKey(id) ? locals.get(id) : null;
133
			final int usedDiskspace = NumberUtils.toInt(doc.valueOf("//USED_DISKSPACE"), 0);
134
			final int handledDataStructures = NumberUtils.toInt(doc.valueOf("//HANDLED_DATASTRUCTURE"), 0);;
135

    
136
			for (final Object o : doc.selectNodes("//SERVICE_PROPERTIES/PROPERTY")) {
137
				final Element p = (Element) o;
138
				props.put(p.valueOf("@key"), p.valueOf("@value"));
139
			}
140

    
141
			return new ServiceRunningInstance(id, url, local, usedDiskspace, handledDataStructures, props);
142
		} catch (final DocumentException e) {
143
			log.error("Error parsing profile: " + profile, e);
144
			throw new RuntimeException("Error parsing profile: " + profile, e);
145
		}
146
	}
147

    
148
	private List<ServiceRunningInstance> findRunningInstances(final String serviceName, final Comparator<ServiceRunningInstance> comparator) {
149
		final List<ServiceRunningInstance> list = findRegisteredServices(serviceName);
150

    
151
		if (list.isEmpty()) {
152
			log.error("Service not found, name: " + serviceName);
153
			throw new RuntimeException("Service not found, name: " + serviceName);
154
		}
155

    
156
		if (comparator != null) {
157
			Collections.sort(list, comparator);
158
		}
159

    
160
		return list;
161
	}
162

    
163
	private List<ServiceRunningInstance> findRegisteredServices(final String serviceName) {
164
		log.debug("searching for service: " + serviceName);
165

    
166
		final String xquery = "for $x in collection('/db/DRIVER/ServiceResources/" + serviceName + "ResourceType') return $x";
167
		log.debug(xquery);
168
		try {
169
			final List<String> services = this.isLookupService.quickSearchProfile(xquery);
170
			final List<ServiceRunningInstance> instances = new ArrayList<>();
171
			final Map<String, BaseService> locals = obtainLocalServices();
172
			if (services != null) {
173
				for (final String source : services) {
174
					final ServiceRunningInstance instance = obtainRunningInstance(source, locals);
175
					instances.add(instance);
176
				}
177
			}
178
			return instances;
179
		} catch (final Exception e) {
180
			throw new IllegalStateException("cannot locate service " + serviceName, e);
181
		}
182
	}
183

    
184
	private Map<String, BaseService> obtainLocalServices() {
185
		final Map<String, BaseService> locals = new HashMap<>();
186

    
187
		this.appContext.getBeansOfType(BaseService.class).values().stream()
188
				.filter(s -> StringUtils.isNotBlank(s.getProfileId()))
189
				.forEach(s -> {
190
					locals.put(s.getProfileId(), s);
191
					log.debug(" -> Service: " + BaseServiceUtils.getServiceName(s.getClass()) + " has id " + s.getProfileId());
192
				});
193
		return locals;
194
	}
195

    
196
	private String obtainServiceProfile(final String profileId) {
197
		final StringWriter sw = new StringWriter();
198
		sw.append("let $uri:=/RESOURCE_PROFILE/HEADER[./RESOURCE_IDENTIFIER/@value='");
199
		sw.append(profileId);
200
		sw.append("']/RESOURCE_URI/@value/string()");
201
		sw.append("\n\n");
202
		sw.append("for $x in collection('/db/DRIVER/ServiceResources')");
203
		sw.append("\n");
204
		sw.append("where $x/RESOURCE_PROFILE/HEADER/RESOURCE_URI/@value = $uri");
205
		sw.append("\n");
206
		sw.append("return $x");
207

    
208
		final String xq = sw.toString();
209

    
210
		try {
211
			return this.isLookupService.getResourceProfileByQuery(xq);
212
		} catch (final ISLookUpException e) {
213
			log.error("cannot locate service using query: " + xq, e);
214
			throw new IllegalStateException("cannot locate service using query: " + xq, e);
215
		}
216
	}
217

    
218
	@Override
219
	public void setApplicationContext(final ApplicationContext appContext) throws BeansException {
220
		this.appContext = appContext;
221
	}
222

    
223
	public Comparator<ServiceRunningInstance> getDefaultComparator() {
224
		return this.defaultComparator;
225
	}
226

    
227
	@Required
228
	public void setDefaultComparator(final Comparator<ServiceRunningInstance> defaultComparator) {
229
		this.defaultComparator = defaultComparator;
230
	}
231

    
232
	public ISLookUpService getIsLookupService() {
233
		return this.isLookupService;
234
	}
235

    
236
	public void setIsLookupService(final ISLookUpService isLookupService) {
237
		this.isLookupService = isLookupService;
238
	}
239

    
240
}
(1-1/3)