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
import javax.annotation.Resource;
8

    
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.Required;
23
import org.springframework.context.ApplicationContext;
24
import org.springframework.context.ApplicationContextAware;
25

    
26
public class DefaultUniqueServiceLocator implements UniqueServiceLocator, ApplicationContextAware {
27

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

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

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

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

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

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

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

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

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

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

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

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

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

    
123
	}
124

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

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

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

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

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

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

    
159
		return list;
160
	}
161

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

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

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

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

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

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

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

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

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

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

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

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

    
239
}
(1-1/3)