Subversion Repositories XServices

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
175 brianR 1
/*
2
 *   Copyright 2014 Brian Rosenberger (Brutex Network)
3
 *
4
 *   Licensed under the Apache License, Version 2.0 (the "License");
5
 *   you may not use this file except in compliance with the License.
6
 *   You may obtain a copy of the License at
7
 *
8
 *       http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 *   Unless required by applicable law or agreed to in writing, software
11
 *   distributed under the License is distributed on an "AS IS" BASIS,
12
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 *   See the License for the specific language governing permissions and
14
 *   limitations under the License.
15
 */
16
 
17
package net.brutex.xservices.ws.rs;
18
 
19
 
20
 
21
import java.io.File;
22
import java.io.IOException;
23
import java.net.MalformedURLException;
24
import java.net.URI;
25
import java.net.URL;
26
import java.nio.file.FileVisitOption;
27
import java.nio.file.Files;
28
import java.nio.file.Path;
29
import java.util.ArrayList;
30
import java.util.EnumSet;
31
import java.util.List;
32
import javax.ws.rs.core.HttpHeaders;
33
import javax.ws.rs.core.Response;
34
import javax.ws.rs.core.UriInfo;
35
 
185 brianR 36
import org.apache.commons.configuration2.PropertiesConfiguration;
37
import org.apache.commons.configuration2.builder.fluent.Configurations;
38
import org.apache.commons.configuration2.ex.ConfigurationException;
39
import org.apache.commons.jcs.JCS;
40
import org.apache.commons.jcs.access.CacheAccess;
41
import org.apache.commons.jcs.access.exception.CacheException;
42
import org.apache.logging.log4j.LogManager;
43
import org.apache.logging.log4j.Logger;
44
 
175 brianR 45
import net.brutex.xservices.cmtypes.ItemType;
46
import net.brutex.xservices.cmtypes.ItemTypeList;
47
import net.brutex.xservices.types.FileInfoType;
48
import net.brutex.xservices.util.FileWalker;
49
 
50
 
51
 
52
/*
53
 * The Serena Dimensions CM Java API is required for these imports.
54
 * The API is not included in this package due to copyright reasons,
55
 * please get Dimensions CM from Serena Software Inc., Evaluation versions
56
 * are available from http://www.serena.com
57
 *
58
 * required Jars:
59
 * serena.darius-14.1.jar
60
 * serena.dmclient-14.1.jar
61
 * serena.dmfile-14.1.jar
62
 * serena.dmnet-14.1.jar
63
 * serena.dmtpi-14.1.jar
64
 *
65
 */
66
 
67
import com.serena.dmclient.api.BulkOperator;
68
import com.serena.dmclient.api.DimensionsConnection;
69
import com.serena.dmclient.api.DimensionsConnectionDetails;
70
import com.serena.dmclient.api.DimensionsConnectionManager;
71
import com.serena.dmclient.api.ItemRevision;
72
import com.serena.dmclient.api.Project;
73
import com.serena.dmclient.api.RepositoryFolder;
74
import com.serena.dmclient.api.SystemAttributes;
75
 
76
/**
77
 * The Class FileInfoImpl.
78
 *
79
 * @author Brian Rosenberger, bru(at)brutex.de
80
 */
81
public class DIMCMInfoImpl implements DIMCMInfo {
82
 
185 brianR 83
	Logger logger = LogManager.getLogger();
175 brianR 84
 
85
	/*
86
	 * (non-Javadoc)
87
	 *
88
	 * @see
89
	 * net.brutex.xservices.ws.rs.FileInfo#getFiles(javax.ws.rs.core.HttpHeaders
90
	 * , java.lang.String, boolean, boolean, int, java.lang.String, int, int)
91
	 */
92
	public Response getFiles(HttpHeaders h, UriInfo uriInfo, String projSpec,
93
			String directory, boolean recursive, boolean withFiles, int level,
94
			String search, int count, int page, boolean useCache) throws CacheException {
95
 
96
 
97
		/*
98
		 * try to hit cache first
99
		 */
185 brianR 100
		CacheAccess<Object, Object> cache = JCS.getInstance("DIMCM");
175 brianR 101
		String cachekey = projSpec + directory + String.valueOf(recursive);
102
		if(useCache) {
103
				ItemTypeList cacheresult = (ItemTypeList) cache.get(cachekey);
104
				if(cacheresult != null) return Response.ok(cacheresult).build();
105
		}
106
 
107
		//Reject when project has not the form "PRODUCT:PROJECT"
108
		if(! projSpec.contains(":")) return Response.noContent().build();
109
 
110
		Project project = getDIMCMConnection().getObjectFactory().getProject(projSpec);
111
		RepositoryFolder folder = null;
112
 
113
		if (directory == null) {
114
			folder = project.getRootFolder();
115
		} else {
116
			while(directory.startsWith("/") || directory.startsWith("\\")) {
117
				directory = directory.substring(1);
118
			}
119
			if(directory.equals("")) {
120
				folder = project.getRootFolder();
121
			} else {
122
				folder = project.findRepositoryFolderByPath(directory);
123
			}
124
		}
125
 
126
 
127
		ItemTypeList resultlist = new ItemTypeList();
128
		resultlist.list = getItems(folder, recursive);
129
		if(cache!=null) cache.put(cachekey, resultlist);
130
 
131
		//does this help?
132
		DimensionsConnectionManager.unregisterThreadConnection();
133
 
134
		return Response.ok(resultlist).build();
135
 
136
	}
137
 
138
 
139
 
140
 
141
	List<ItemType> getItems(RepositoryFolder f, boolean recursive) {
142
		DimensionsConnection conn = getDIMCMConnection();
143
		List<ItemType> result = new ArrayList<>();
144
 
145
		/* get Items from current folder */
146
		/* latest revision only */
147
		List<ItemRevision> revisions = f.getLatestItemRevisions();
148
 
149
		int[] attr = { SystemAttributes.FULL_PATH_NAME,
150
				SystemAttributes.ITEMFILE_DIR,
151
				SystemAttributes.ITEMFILE_FILENAME,
152
				SystemAttributes.ITEMFILE_DIR, SystemAttributes.OBJECT_SPEC,
153
				SystemAttributes.OBJECT_ID, SystemAttributes.OBJECT_SPEC_UID,
154
				SystemAttributes.OBJECT_UID, SystemAttributes.CREATION_DATE,
155
				SystemAttributes.CREATION_USER, SystemAttributes.ITEM_FORMAT,
156
				SystemAttributes.LAST_UPDATED_DATE,
157
				SystemAttributes.LAST_UPDATED_USER };
158
		BulkOperator bulk = conn.getObjectFactory().getBulkOperator(revisions);
159
		bulk.queryAttribute(attr);
160
 
161
		// Copy into JAXB object
162
		for (ItemRevision r : revisions) {
163
			ItemType item = new ItemType();
164
			item.setLongFilename((String) r
165
					.getAttribute(SystemAttributes.FULL_PATH_NAME));
166
			item.setDirName((String) r
167
					.getAttribute(SystemAttributes.ITEMFILE_DIR));
168
			item.setShortFilename((String) r
169
					.getAttribute(SystemAttributes.ITEMFILE_FILENAME));
170
			item.setObject_id((String) r
171
					.getAttribute(SystemAttributes.OBJECT_ID));
172
			item.setObject_uid((String.valueOf(r
173
					.getAttribute(SystemAttributes.OBJECT_UID))));
174
			item.setObject_spec((String) r
175
					.getAttribute(SystemAttributes.OBJECT_SPEC));
176
			item.setObject_spec_uid(String.valueOf(r
177
					.getAttribute(SystemAttributes.OBJECT_SPEC_UID)));
178
			item.setObject_spec_uid(String.valueOf(r
179
					.getAttribute(SystemAttributes.OBJECT_SPEC_UID)));
180
			item.setCreatedDate(String.valueOf(r
181
					.getAttribute(SystemAttributes.CREATION_DATE)));
182
			item.setCreatedUser(String.valueOf(r
183
					.getAttribute(SystemAttributes.CREATION_USER)));
184
			item.setItemFormat(String.valueOf(r
185
					.getAttribute(SystemAttributes.ITEM_FORMAT)));
186
			item.setUpdatedDate(String.valueOf(r
187
					.getAttribute(SystemAttributes.LAST_UPDATED_DATE)));
188
			item.setUpdatedUser(String.valueOf(r
189
					.getAttribute(SystemAttributes.LAST_UPDATED_USER)));
190
 
191
			try {
192
				item.setUrl(new URL(getBaseURL()
193
						+ "?jsp=api&command=openi&object_id="
194
						+ item.getObject_spec() + "&DB_CONN="
195
						+ conn.getConnectionDetails().getDbConn() + "&DB_NAME="
196
						+ conn.getConnectionDetails().getDbName()));
197
			} catch (MalformedURLException e) {
198
				// TODO Auto-generated catch block
199
				e.printStackTrace();
200
			}
201
			result.add(item);
202
		}
203
 
204
		/*
205
		 * for recursive add other folders
206
		 */
207
		if(recursive) {
208
			List<RepositoryFolder> folders = f.getAllChildFolders();
209
			for(RepositoryFolder ff : folders) {
210
				result.addAll(getItems(ff, false));
211
			}
212
		}
213
 
214
		return result;
215
	}
216
 
217
	/**
218
	 * Sets the directory.
219
	 *
220
	 * @param list
221
	 *            the list
222
	 * @param dir
223
	 *            the dir
224
	 * @param withDirectories
225
	 *            the with directories
226
	 * @param withFiles
227
	 *            the with files
228
	 * @param depth
229
	 *            the depth
230
	 * @param search
231
	 *            the search
232
	 */
233
	private void setDirectory(final URI baseuri, final List<FileInfoType> list,
234
			File dir, boolean withDirectories, boolean withFiles,
235
			final int depth, String search) {
236
		if (depth <= 0)
237
			return;
238
 
239
		if (search == null || search.equals("")) {
240
			search = "*";
241
			logger.info("No search pattern supplied, using default '*'.");
242
		}
243
 
244
		FileWalker finder = new FileWalker(search);
245
		try {
246
			Files.walkFileTree(dir.toPath(),
247
					EnumSet.of(FileVisitOption.FOLLOW_LINKS), depth, finder);
248
			logger.info("FileWalker returned '" + finder.getCount()
249
					+ "' hits. '" + finder.getTotal()
250
					+ "' files have been scanned.");
251
			List<Path> result = finder.getResult();
252
			for (Path f : result) {
253
				if (!withDirectories) {
254
					if (f.toFile().isDirectory())
255
						continue;
256
				}
257
				if (!withFiles) {
258
					if (f.toFile().isFile())
259
						continue;
260
				}
261
				list.add(new FileInfoType(f, baseuri));
262
			}
263
		} catch (IOException e2) {
264
			logger.error(e2.getMessage(), e2);
265
			;
266
		}
267
	}
268
 
269
	/**
270
	 * Sets the directory.
271
	 *
272
	 * @param dir
273
	 *            the dir
274
	 * @param withDirectories
275
	 *            the with directories
276
	 * @param withFiles
277
	 *            the with files
278
	 * @param depth
279
	 *            the depth
280
	 * @param search
281
	 *            the search
282
	 * @return the list
283
	 */
284
	private List<FileInfoType> setDirectory(URI baseuri, String dir,
285
			boolean withDirectories, boolean withFiles, int depth, String search) {
286
		List<FileInfoType> list = new ArrayList<FileInfoType>();
287
		setDirectory(baseuri, list, new File(dir), withDirectories, withFiles,
288
				depth, search);
289
		return list;
290
	}
291
 
292
	private boolean isPermitted(String dir) {
293
		/*
294
		 *
295
		 * logger.warn(String.format(
296
		 * "User '%s' does not have permission to access '%s'."
297
		 * ,SecurityUtils.getSubject().getPrincipal(), dir )); throw new
298
		 * NotAuthorizedException(new
299
		 * UnauthorizedException("User does not have permission to access "+
300
		 * dir)); }
301
		 */
302
		return true;
303
	}
304
 
305
	// http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java
306
	private static String humanReadableByteCount(long bytes, boolean si) {
307
		int unit = si ? 1000 : 1024;
308
		if (bytes < unit)
309
			return bytes + " B";
310
		int exp = (int) (Math.log(bytes) / Math.log(unit));
311
		String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1)
312
				+ (si ? "" : "i");
313
		return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
314
	}
315
 
316
	private DimensionsConnection getDIMCMConnection() {
317
		/*
318
		 * Do we have a registered connection already?
319
		 */
320
		DimensionsConnection conn = null;
321
 
322
		try {
323
			conn = DimensionsConnectionManager.getThreadConnection();
324
			if (conn != null)
325
				return conn;
326
		} catch (Exception e) {
327
			logger.error(e.getMessage());
328
		}
329
 
330
		/*
331
		 * Create a new connection from property file
332
		 */
333
		PropertiesConfiguration props;
334
		try {
185 brianR 335
 
336
			props = new Configurations().properties(this.getClass()
175 brianR 337
					.getClassLoader().getResource("/../dimcm.properties"));
338
		} catch (ConfigurationException e) {
339
			e.printStackTrace();
340
			return null;
341
		}
342
 
343
		DimensionsConnectionDetails details = new DimensionsConnectionDetails();
344
		details.setUsername(props.getString("user"));
345
		details.setPassword(props.getString("password"));
346
		details.setDbName(props.getString("dbname"));
347
		details.setDbConn(props.getString("dbconn"));
348
		details.setServer(props.getString("server"));
349
		conn = DimensionsConnectionManager.getConnection(details);
350
		DimensionsConnectionManager.registerThreadConnection(conn);
351
		return conn;
352
	}
353
 
354
	private String getBaseURL() {
355
		final String CACHE_BASEURL = "DIMCM.conf.baseurl";
356
	try {
185 brianR 357
		CacheAccess<Object, Object> cache = JCS.getInstance("DIMCM");
175 brianR 358
		String baseurl = (String) cache.get(CACHE_BASEURL);
359
		if(baseurl != null) return baseurl;
360
 
185 brianR 361
		Configurations configs = new Configurations();
362
 
363
		PropertiesConfiguration	props = configs.properties((this.getClass().getClassLoader().getResource("/../dimcm.properties")));
175 brianR 364
		baseurl = props.getString("baseurl");
365
		cache.put(CACHE_BASEURL, baseurl);
366
		return baseurl;
367
 
368
	} catch (CacheException e1) {
369
		// TODO Auto-generated catch block
370
		e1.printStackTrace();
371
		return null;
372
	} catch (ConfigurationException e) {
373
		e.printStackTrace();
374
		return null;
375
 
376
	}
377
}
378
}