diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/EntitySynchronizer.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/EntitySynchronizer.java index f9152d3b38095a54cef8c5ac62cdb82f1d5c2462..c52737eaa3d983557429b636506e93f8dfdf6683 100644 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/EntitySynchronizer.java +++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/EntitySynchronizer.java @@ -39,6 +39,7 @@ import org.apache.commons.codec.binary.Hex; import org.apache.commons.collections4.map.MultiKeyMap; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.time.StopWatch; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.w3c.dom.Document; @@ -84,6 +85,7 @@ import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronize import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.translator.INameTranslator; import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.translator.PrefixBasedNameTranslator; import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.util.DSPropertyUtils; +import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.util.Monitor; import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.util.V3Utils; import ch.systemsx.cisd.cifex.shared.basic.UserFailureException; import ch.systemsx.cisd.common.concurrent.ParallelizedExecutor; @@ -198,6 +200,7 @@ public class EntitySynchronizer private void registerDataSets(ResourceListParserData data, List<String> notSyncedAttachmentsHolders) throws IOException { + Monitor monitor = new Monitor("Register data sets", operationLog); // register physical data sets without any hierarchy // Note that container/component and parent/child relationships are established post-reg. // setParentDataSetsOnTheChildren(data); @@ -237,10 +240,12 @@ public class EntitySynchronizer skippedDataSets.addAll(notRegisteredDataSetCodes); skippedDataSets.addAll(blackListedDataSetCodes); establishDataSetRelationships(data.getDataSetsToProcess(), skippedDataSets, physicalDSMap); + monitor.log(); } private List<String> registerAttachments(ResourceListParserData data, MultiKeyMap<String, String> newEntities) { + Monitor monitor = new Monitor("Register attachments", operationLog); operationLog.info("Processing attachments..."); List<IncomingEntity<?>> attachmentHoldersToProcess = data.filterAttachmentHoldersByLastModificationDate(lastSyncTimestamp, attachmentHolderCodesToRetry); @@ -262,12 +267,14 @@ public class EntitySynchronizer : "synchronization of attachments for " + notSyncedAttachmentsHolders.size() + " entitities FAILED.")); } + monitor.log(); return notSyncedAttachmentsHolders; } private MultiKeyMap<String, String> registerEntities(ResourceListParserData data) { - AtomicEntityOperationDetails entityOperationDetails = createEntityOperationDetails(data); + Monitor monitor = new Monitor("Register entities", operationLog); + AtomicEntityOperationDetails entityOperationDetails = createEntityOperationDetails(data, monitor); MultiKeyMap<String, String> newEntities = new MultiKeyMap<String, String>(); if (config.isDryRun() == false) @@ -276,17 +283,18 @@ public class EntitySynchronizer newEntities = getNewEntities(entityOperationDetails); operationLog.info("Entity operation result: " + operationResult); } + monitor.log(); return newEntities; } - private AtomicEntityOperationDetails createEntityOperationDetails(ResourceListParserData data) + private AtomicEntityOperationDetails createEntityOperationDetails(ResourceListParserData data, Monitor monitor) { AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder(); processSpaces(data, builder); processProjects(data, builder); processExperiments(data, builder); - processSamples(data, builder); + processSamples(data, builder, monitor); processMaterials(data, builder); AtomicEntityOperationDetails entityOperationDetails = builder.getDetails(); @@ -311,24 +319,26 @@ public class EntitySynchronizer private ResourceListParserData parseResourceList(Document doc) throws XPathExpressionException { + Monitor monitor = new Monitor("Parsing resource list", operationLog); // Parse the resource list: This sends back all projects, // experiments, samples and data sets contained in the XML together with their last modification date to be used for filtering operationLog.info("Parsing the resource list xml document..."); INameTranslator nameTranslator = new PrefixBasedNameTranslator(config.getDataSourceAlias()); ResourceListParser parser = ResourceListParser.create(nameTranslator, dataStoreCode); - ResourceListParserData data = parser.parseResourceListDocument(doc); + ResourceListParserData data = parser.parseResourceListDocument(doc, monitor); + monitor.log(); return data; } private Document getResourceList() throws Exception { - + Monitor monitor = new Monitor("Retrieving resoure list", operationLog); DataSourceConnector dataSourceConnector = new DataSourceConnector(config.getDataSourceURI(), config.getAuthenticationCredentials(), operationLog); - operationLog.info("\nRetrieving the resource list..."); + operationLog.info("Retrieving the resource list..."); Document doc = dataSourceConnector.getResourceListAsXMLDoc(Arrays.asList(ArrayUtils.EMPTY_STRING_ARRAY)); - + monitor.log(); return doc; } @@ -736,6 +746,7 @@ public class EntitySynchronizer private void registerMasterData(MasterData masterData) { + Monitor monitor = new Monitor("Register master data", operationLog); operationLog.info("Registering master data..."); if (config.isVerbose() == true) { @@ -753,6 +764,7 @@ public class EntitySynchronizer MasterDataSynchronizer masterDataSyncronizer = new MasterDataSynchronizer(config.getHarvesterUser(), config.getHarvesterPass(), config.isDryRun(), config.isVerbose(), operationLog); masterDataSyncronizer.synchronizeMasterData(masterData); + monitor.log(); } private void verboseLogMasterData(Set<String> types, String typeName) @@ -769,6 +781,7 @@ public class EntitySynchronizer private void processDeletions(ResourceListParserData data) throws NoSuchAlgorithmException, UnsupportedEncodingException { + Monitor monitor = new Monitor("Delete entities", operationLog); String sessionToken = ServiceProvider.getOpenBISService().getSessionToken(); IEntityRetriever entityRetriever = SkinnyEntityRetriever.createWithSessionToken(ServiceProvider.getV3ApplicationService(), sessionToken); @@ -899,6 +912,7 @@ public class EntitySynchronizer if (config.isDryRun() == true) { + monitor.log(); return; } @@ -980,6 +994,7 @@ public class EntitySynchronizer getDirectoryProvider().getDataSetDirectory(physicalDS); SegmentedStoreUtils.deleteDataSetInstantly(physicalDS.getCode(), datasetDir, new Log4jSimpleLogger(operationLog)); } + monitor.log(); } private void verboseLogDeletions(Collection<String> identifiers, String entityKind) @@ -1170,14 +1185,20 @@ public class EntitySynchronizer return prjUpdate; } - private void processSamples(ResourceListParserData data, AtomicEntityOperationDetailsBuilder builder) + private void processSamples(ResourceListParserData data, AtomicEntityOperationDetailsBuilder builder, Monitor monitor) { // process samples Map<String, IncomingSample> samplesToProcess = data.getSamplesToProcess(); Map<SampleIdentifier, NewSample> samplesToUpdate = new HashMap<SampleIdentifier, NewSample>(); Set<String> sampleWithUpdatedParents = new HashSet<String>(); + int count = 0; + int n = samplesToProcess.size(); for (IncomingSample sample : samplesToProcess.values()) { + if (++count % 100 == 0) + { + monitor.log(String.format("%7d/%d sample: %s", count, n, sample.getIdentifer())); + } NewSample incomingSample = sample.getSample(); if (sample.getLastModificationDate().after(lastSyncTimestamp)) { diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/ResourceListParser.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/ResourceListParser.java index cef2b91320e6a5a9af54eab8413bf78e3dd2046f..e55a13d8399de4f277bf0ef339e7f451e59b211e 100644 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/ResourceListParser.java +++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/ResourceListParser.java @@ -26,7 +26,9 @@ import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.TimeZone; +import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -55,6 +57,7 @@ import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronize import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.ResourceListParserData.MaterialWithLastModificationDate; import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.translator.DefaultNameTranslator; import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.translator.INameTranslator; +import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.util.Monitor; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataTypeCode; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityProperty; @@ -112,7 +115,71 @@ public class ResourceListParser return create(new DefaultNameTranslator(), dataStoreCode); } - public ResourceListParserData parseResourceListDocument(Document doc) throws XPathExpressionException + public ResourceListParserData parseResourceListDocument(Document doc, Monitor monitor) throws XPathExpressionException + { + XPath xpath = createXPath(); + Date resourceListTimestamp = getResourceListTimestamp(doc, xpath); + data.setResourceListTimestamp(resourceListTimestamp); + + monitor.log(); + NodeList nodes = doc.getDocumentElement().getChildNodes(); + for (int i = 0; i < nodes.getLength(); i++) + { + Node node = nodes.item(i); + Map<String, List<Node>> childrenByType = getChildrenByType(node); + List<Node> locNodes = childrenByType.get("loc"); + if (locNodes == null) + { + continue; + } + String uri = locNodes.get(0).getTextContent(); + if (uri.endsWith("MASTER_DATA/MASTER_DATA/M")) + { + parseMasterData(doc, xpath, uri); + } + } + for (int i = 0, n = nodes.getLength(); i < n; i++) + { + Node node = nodes.item(i); + Map<String, List<Node>> childrenByType = getChildrenByType(node); + List<Node> locNodes = childrenByType.get("loc"); + if (locNodes == null) + { + continue; + } + String uri = locNodes.get(0).getTextContent(); + if (uri.endsWith("MASTER_DATA/MASTER_DATA/M") == false && uri.endsWith("/M")) + { + List<Node> lastmodNodes = childrenByType.get("lastmod"); + if (lastmodNodes == null) + { + continue; + } + String lastModDataStr = lastmodNodes.get(0).getTextContent().trim(); + try + { + Date lastModificationDate = convertFromW3CDate(lastModDataStr); + List<Node> xdNodes = childrenByType.get("x:xd"); + if (xdNodes == null) + { + continue; + } + if ((i + 1) % 10000 == 0) + { + monitor.log(String.format("%7d/%d uri: %s", i + 1, n, uri)); + } + parseMetaData(uri, lastModificationDate, xdNodes.get(0)); + } catch (ParseException e) + { + throw new XPathExpressionException("Last modification date cannot be parsed:" + lastModDataStr); + } + } + } + + return data; + } + + private XPath createXPath() { XPath xpath = XPathFactory.newInstance().newXPath(); xpath.setNamespaceContext(new NamespaceContext() @@ -144,16 +211,7 @@ public class ResourceListParser throw new UnsupportedOperationException("Not implemented!!!"); } }); - Date resourceListTimestamp = getResourceListTimestamp(doc, xpath); - data.setResourceListTimestamp(resourceListTimestamp); - - List<String> uris = getResourceLocations(doc, xpath); - for (String uri : uris) - { - parseUriMetaData(doc, xpath, uri); - } - - return data; + return xpath; } private Date getResourceListTimestamp(Document doc, XPath xpath) throws XPathExpressionException @@ -170,27 +228,6 @@ public class ResourceListParser } } - private List<String> getResourceLocations(Document doc, XPath xpath) throws XPathExpressionException - { - XPathExpression expr = xpath.compile("/s:urlset/s:url/s:loc");// "//*[local-name()='loc']/text()"); //"//s:loc/text()" - - Object result = expr.evaluate(doc, XPathConstants.NODESET); - NodeList nodes = (NodeList) result; - List<String> list = new ArrayList<String>(); - for (int i = 0; i < nodes.getLength(); i++) - { - String uri = nodes.item(i).getTextContent(); - if (uri.endsWith("MASTER_DATA/MASTER_DATA/M")) - { - parseMasterData(doc, xpath, uri); - } else if (uri.endsWith("/M")) - { - list.add(uri); - } - } - return list; - } - private void parseMasterData(Document doc, XPath xpath, String uri) throws XPathExpressionException { MasterDataParser mdParser = MasterDataParser.create(nameTranslator); @@ -207,48 +244,48 @@ public class ResourceListParser masterData.setPropertyAssignmentsToProcess(mdParser.getEntityPropertyAssignments()); } - private void parseUriMetaData(Document doc, XPath xpath, String uri) throws XPathExpressionException + private void parseMetaData(String uri, Date lastModificationDate, Node xdNode) throws XPathExpressionException { - Date lastModificationDate = extractLastModificationDate(doc, xpath, uri); - - Node xdNode = extractXdNode(doc, xpath, uri); String entityKind = xdNode.getAttributes().getNamedItem("kind").getTextContent(); if (SyncEntityKind.PROJECT.getLabel().equals(entityKind)) { - parseProjectMetaData(xpath, extractPermIdFromURI(uri), xdNode, lastModificationDate); + parseProjectMetaData(extractPermIdFromURI(uri), xdNode, lastModificationDate); } else if (SyncEntityKind.EXPERIMENT.getLabel().equals(entityKind)) { - parseExperimentMetaData(xpath, extractPermIdFromURI(uri), xdNode, lastModificationDate); + parseExperimentMetaData(extractPermIdFromURI(uri), xdNode, lastModificationDate); } else if (SyncEntityKind.SAMPLE.getLabel().equals(entityKind)) { - parseSampleMetaData(xpath, extractPermIdFromURI(uri), xdNode, lastModificationDate); + parseSampleMetaData(extractPermIdFromURI(uri), xdNode, lastModificationDate); } else if (SyncEntityKind.DATA_SET.getLabel().equals(entityKind)) { - parseDataSetMetaData(xpath, extractDataSetCodeFromURI(uri), xdNode, lastModificationDate); + parseDataSetMetaData(extractDataSetCodeFromURI(uri), xdNode, lastModificationDate); } else if (SyncEntityKind.MATERIAL.getLabel().equals(entityKind)) { - parseMaterialMetaData(xpath, extractMaterialCodeFromURI(uri), xdNode, lastModificationDate); + parseMaterialMetaData(extractMaterialCodeFromURI(uri), xdNode, lastModificationDate); } } - private Date extractLastModificationDate(Document doc, XPath xpath, String uri) throws XPathExpressionException + private Map<String, List<Node>> getChildrenByType(Node node) { - XPathExpression expr = xpath.compile("//s:url/s:loc[normalize-space(.)='" + uri + "']//following-sibling::s:lastmod[1]"); - Node lastModNode = (Node) expr.evaluate(doc, XPathConstants.NODE); - if (lastModNode == null) + Map<String, List<Node>> result = new TreeMap<>(); + if (node.hasChildNodes()) { - throw new XPathExpressionException("The resource list should contain 1 lastmod element per resource"); - } - - String lastModDataStr = lastModNode.getTextContent().trim(); - try - { - return convertFromW3CDate(lastModDataStr); - } catch (ParseException e) - { - throw new XPathExpressionException("Last modification date cannot be parsed:" + lastModDataStr); + NodeList childNodes = node.getChildNodes(); + for (int i = 0, n = childNodes.getLength(); i < n; i++) + { + Node childNode = childNodes.item(i); + String nodeName = childNode.getNodeName().toLowerCase(); + List<Node> list = result.get(nodeName); + if (list == null) + { + list = new ArrayList<>(); + result.put(nodeName, list); + } + list.add(childNode); + } } + return result; } private Date convertFromW3CDate(String lastModDataStr) throws ParseException @@ -258,19 +295,7 @@ public class ResourceListParser return df1.parse(lastModDataStr); } - private Node extractXdNode(Document doc, XPath xpath, String uri) throws XPathExpressionException - { - // alternative expression: //s:url/s:loc[normalize-space(.)='" + uri + "']/../x:xd"); - XPathExpression expr = xpath.compile("//s:url/s:loc[normalize-space(.)='" + uri + "']//following-sibling::x:xd[1]"); - Node xdNode = (Node) expr.evaluate(doc, XPathConstants.NODE); - if (xdNode == null) - { - throw new XPathExpressionException("The resource list should contain 1 xd element per resource"); - } - return xdNode; - } - - private void parseDataSetMetaData(XPath xpath, String permId, Node xdNode, Date lastModificationDate) + private void parseDataSetMetaData(String permId, Node xdNode, Date lastModificationDate) { String code = extractCode(xdNode); String sampleIdentifier = extractAttribute(xdNode, "sample", true); @@ -299,8 +324,8 @@ public class ResourceListParser IncomingDataSet incomingDataSet = new IncomingDataSet(ds, lastModificationDate); data.getDataSetsToProcess().put(permId, incomingDataSet); - incomingDataSet.setConnections(parseConnections(xpath, xdNode)); - ds.setDataSetProperties(parseDataSetProperties(xpath, xdNode)); + incomingDataSet.setConnections(parseConnections(xdNode)); + ds.setDataSetProperties(parseDataSetProperties(xdNode)); } private String extractAttribute(Node xdNode, String attrName, boolean nullAllowed) @@ -366,7 +391,7 @@ public class ResourceListParser expCode); } - private void parseProjectMetaData(XPath xpath, String permId, Node xdNode, Date lastModificationDate) + private void parseProjectMetaData(String permId, Node xdNode, Date lastModificationDate) { String code = extractCode(xdNode); @@ -377,8 +402,8 @@ public class ResourceListParser newProject.setPermID(permId); IncomingProject incomingProject = new IncomingProject(newProject, lastModificationDate); data.getProjectsToProcess().put(permId, incomingProject); - incomingProject.setConnections(parseConnections(xpath, xdNode)); - incomingProject.setHasAttachments(hasAttachments(xpath, xdNode)); + incomingProject.setConnections(parseConnections(xdNode)); + incomingProject.setHasAttachments(hasAttachments(xdNode)); } private ExperimentIdentifier createExperimentIdentifier(String spaceId, String prjCode, String expCode) @@ -415,7 +440,7 @@ public class ResourceListParser return new SpaceIdentifier(translatedSpaceId); } - private void parseMaterialMetaData(XPath xpath, String permId, Node xdNode, Date lastModificationDate) + private void parseMaterialMetaData(String permId, Node xdNode, Date lastModificationDate) { String code = nameTranslator.translate(extractCode(xdNode)); String type = extractType(xdNode); @@ -423,10 +448,10 @@ public class ResourceListParser MaterialWithLastModificationDate materialWithLastModDate = new MaterialWithLastModificationDate(newMaterial, lastModificationDate); data.getMaterialsToProcess().put(code, type, materialWithLastModDate); - newMaterial.setProperties(parseProperties(xpath, xdNode)); + newMaterial.setProperties(parseProperties(xdNode)); } - private List<Connection> parseConnections(XPath xpath, Node xdNode) + private List<Connection> parseConnections(Node xdNode) { List<Connection> conns = new ArrayList<Connection>(); Element docElement = (Element) xdNode; @@ -445,21 +470,17 @@ public class ResourceListParser return conns; } - private boolean hasAttachments(XPath xpath, Node xdNode) + private boolean hasAttachments(Node xdNode) { Element docElement = (Element) xdNode; NodeList connsNode = docElement.getElementsByTagName("x:binaryData"); // if a sample/experiment/project node has binaryData element, it can only be because of attachments - if (connsNode.getLength() == 1) - { - return true; - } - return false; + return connsNode.getLength() == 1; } - private List<NewProperty> parseDataSetProperties(XPath xpath, Node xdNode) + private List<NewProperty> parseDataSetProperties(Node xdNode) { - EntityProperty[] entityProperties = parseProperties(xpath, xdNode); + EntityProperty[] entityProperties = parseProperties(xdNode); List<NewProperty> dsProperties = new ArrayList<NewProperty>(); for (EntityProperty entityProperty : entityProperties) { @@ -468,7 +489,7 @@ public class ResourceListParser return dsProperties; } - private EntityProperty[] parseProperties(XPath xpath, Node xdNode) + private EntityProperty[] parseProperties(Node xdNode) { List<EntityProperty> entityProperties = new ArrayList<EntityProperty>(); @@ -533,7 +554,7 @@ public class ResourceListParser return new MaterialIdentifier(code, typeCode).toString(); } - private void parseExperimentMetaData(XPath xpath, String permId, Node xdNode, Date lastModificationDate) + private void parseExperimentMetaData(String permId, Node xdNode, Date lastModificationDate) { String code = extractCode(xdNode); String type = extractType(xdNode); @@ -544,12 +565,12 @@ public class ResourceListParser newExp.setPermID(permId); IncomingExperiment incomingExperiment = new IncomingExperiment(newExp, lastModificationDate); data.getExperimentsToProcess().put(permId, incomingExperiment); - incomingExperiment.setConnections(parseConnections(xpath, xdNode)); - incomingExperiment.setHasAttachments(hasAttachments(xpath, xdNode)); - newExp.setProperties(parseProperties(xpath, xdNode)); + incomingExperiment.setConnections(parseConnections(xdNode)); + incomingExperiment.setHasAttachments(hasAttachments(xdNode)); + newExp.setProperties(parseProperties(xdNode)); } - private void parseSampleMetaData(XPath xpath, String permId, Node xdNode, Date lastModificationDate) + private void parseSampleMetaData(String permId, Node xdNode, Date lastModificationDate) { String code = extractCode(xdNode); String type = extractType(xdNode); @@ -585,9 +606,9 @@ public class ResourceListParser } IncomingSample incomingSample = new IncomingSample(newSample, lastModificationDate); data.getSamplesToProcess().put(permId, incomingSample); - incomingSample.setHasAttachments(hasAttachments(xpath, xdNode)); - incomingSample.setConnections(parseConnections(xpath, xdNode)); - newSample.setProperties(parseProperties(xpath, xdNode)); + incomingSample.setHasAttachments(hasAttachments(xdNode)); + incomingSample.setConnections(parseConnections(xdNode)); + newSample.setProperties(parseProperties(xdNode)); } private String extractType(Node xdNode) diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/util/Monitor.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/util/Monitor.java new file mode 100644 index 0000000000000000000000000000000000000000..36d8202f2cd02a0eea63938c765fbd9cb339b566 --- /dev/null +++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/util/Monitor.java @@ -0,0 +1,74 @@ +/* + * Copyright 2018 ETH Zuerich, SIS + * + * 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 ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.util; + +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.time.StopWatch; +import org.apache.log4j.Logger; + +import ch.systemsx.cisd.common.filesystem.FileUtilities; +import ch.systemsx.cisd.common.logging.BufferedAppender; +import ch.systemsx.cisd.common.logging.LogCategory; +import ch.systemsx.cisd.common.logging.LogFactory; +import ch.systemsx.cisd.openbis.util.LogRecordingUtils; + +/** + * @author Franz-Josef Elmer + */ +public class Monitor +{ + private String name; + + private Logger operationLog; + + private StopWatch stopWatch; + + public Monitor(String name, Logger operationLog) + { + this.name = name; + this.operationLog = operationLog; + stopWatch = new StopWatch(); + stopWatch.start(); + operationLog.info("-------- monitoring started for '" + name + "'."); + } + + public void log() + { + logInfo(createReport()); + } + + public void log(String message) + { + logInfo(createReport() + " " + message); + } + + private void logInfo(String info) + { + operationLog.info("[" + name + "] " + info); + } + + private String createReport() + { + Runtime runtime = Runtime.getRuntime(); + String max = FileUtilities.byteCountToDisplaySize(runtime.maxMemory()); + String free = FileUtilities.byteCountToDisplaySize(runtime.freeMemory()); + String used = FileUtilities.byteCountToDisplaySize(runtime.maxMemory() - runtime.freeMemory()); + long time = stopWatch.getTime(TimeUnit.SECONDS); + return String.format("[time: %5d sec, used: %9s, free: %9s, max: %9s]", time, used, free, max); + } +}