diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/DataSetRegistrationTask.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/DataSetRegistrationTask.java deleted file mode 100644 index a88b213f9d57aac0faca7628ee30fd33980bc360..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/DataSetRegistrationTask.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright 2016 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. - */ -//TODO should we use permId in hash tables instead of identifier, fore exp in samplesToUpdate -//TODO try to implement sample relationship sync like DS rel. sync -//TODO check if already loaded harvesterEntityGraph can be used in most cases -//TODO check if harvesterEntityGraph can be partially loaded as required -//TODO correctly handle saving of last sync timestamp -//TODO different last sync timestamp files for different plugins - -//this is actually handled by setting up different harvester plugins with different files -//TODO when deleting make sure we are not emptying all the trash but just the ones we synchronized -//TODO checksum checkss for data set files -package ch.ethz.sis.openbis.generic.server.dss.plugins.harvester; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Properties; -import java.util.Set; - -import javax.activation.DataHandler; -import javax.activation.DataSource; -import javax.mail.util.ByteArrayDataSource; - -import org.apache.log4j.Logger; - -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.config.SyncConfig; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.config.SynchronizationConfigReader; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.EntitySynchronizer; -import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel; -import ch.systemsx.cisd.common.filesystem.FileUtilities; -import ch.systemsx.cisd.common.logging.LogCategory; -import ch.systemsx.cisd.common.logging.LogFactory; -import ch.systemsx.cisd.common.mail.EMailAddress; -import ch.systemsx.cisd.common.mail.IMailClient; -import ch.systemsx.cisd.common.maintenance.IMaintenanceTask; -import ch.systemsx.cisd.common.parser.ILine; -import ch.systemsx.cisd.common.parser.filter.ExcludeEmptyAndCommentLineFilter; -import ch.systemsx.cisd.common.parser.filter.ILineFilter; -import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.PluginTaskInfoProvider; -import ch.systemsx.cisd.openbis.dss.generic.shared.DataSetProcessingContext; -import ch.systemsx.cisd.openbis.dss.generic.shared.IConfigProvider; -import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; -import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; -import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; -import ch.systemsx.cisd.openbis.dss.generic.shared.utils.DssPropertyParametersUtil; - -/** - * @author Ganime Betul Akin - */ -public class DataSetRegistrationTask<T extends DataSetInformation> implements IMaintenanceTask -{ - protected static final Logger operationLog = - LogFactory.getLogger(LogCategory.OPERATION, DataSetRegistrationTask.class); - - final DateFormat formatter = new SimpleDateFormat("dd-MM-yy HH-mm-ss", Locale.ENGLISH); - - private static final String HARVESTER_CONFIG_FILE_PROPERTY_NAME = "harvester-config-file"; - - private static final String DEFAULT_HARVESTER_CONFIG_FILE_NAME = "../../harvester-config.txt"; - - private File storeRoot; - - private IEncapsulatedOpenBISService service; - - private DataSetProcessingContext context; - - private Date lastSyncTimestamp; - - private File harvesterConfigFile; - - private IMailClient mailClient; - - private String dataStoreCode; - - @Override - public void setUp(String pluginName, Properties properties) - { - service = ServiceProvider.getOpenBISService(); - context = new DataSetProcessingContext(null, null, null, null, null, null); - dataStoreCode = getConfigProvider().getDataStoreCode(); - storeRoot = new File(DssPropertyParametersUtil.loadServiceProperties().getProperty(PluginTaskInfoProvider.STOREROOT_DIR_KEY)); - mailClient = ServiceProvider.getDataStoreService().createEMailClient(); - - - String configFileProperty = properties.getProperty(HARVESTER_CONFIG_FILE_PROPERTY_NAME); - if (configFileProperty == null) - { - harvesterConfigFile = - new File(getConfigProvider().getStoreRoot(), DEFAULT_HARVESTER_CONFIG_FILE_NAME); - } else - { - harvesterConfigFile = new File(configFileProperty); - } - } - - private IConfigProvider getConfigProvider() - { - return ServiceProvider.getConfigProvider(); - } - - @Override - public void execute() - { - operationLog.info(this.getClass() + " started."); - - SynchronizationConfigReader syncConfigReader = new SynchronizationConfigReader(); - List<SyncConfig> configs; - try - { - configs = syncConfigReader.readConfiguration(harvesterConfigFile, operationLog); - } catch (Exception e) - { - operationLog.error("", e); - return; - } - - for (SyncConfig config : configs) - { - try - { - operationLog - .info("Start synchronization from data source: " + config.getDataSourceOpenbisURL() + " for user " + config.getUser()); - - String fileName = config.getLastSyncTimestampFileName(); - File lastSyncTimestampFile = new File(fileName); - lastSyncTimestamp = getLastSyncTimeStamp(lastSyncTimestampFile); - - String notSyncedDataSetsFileName = config.getNotSyncedDataSetsFileName(); - Set<String> notSyncedDataSetCodes = getNotSyncedDataSetCodes(notSyncedDataSetsFileName); - Set<String> blackListedDataSetCodes = getBlackListedDataSetCodes(notSyncedDataSetsFileName); - - // save the current time into a temp file as last sync time - File newLastSyncTimeStampFile = new File(fileName + ".new"); - Date syncStartTimestamp = new Date(); - FileUtilities.writeToFile(newLastSyncTimeStampFile, formatter.format(syncStartTimestamp)); - - EntitySynchronizer synchronizer = - new EntitySynchronizer(service, dataStoreCode, storeRoot, lastSyncTimestamp, notSyncedDataSetCodes, blackListedDataSetCodes, - context, config, - operationLog); - Date resourceListTimestamp = synchronizer.syncronizeEntities(); - if (resourceListTimestamp.before(syncStartTimestamp)) - { - FileUtilities.writeToFile(newLastSyncTimeStampFile, formatter.format(resourceListTimestamp)); - } - - operationLog.info("Saving the timestamp of sync start to file"); - saveSyncTimestamp(newLastSyncTimeStampFile, lastSyncTimestampFile); - - operationLog.info(this.getClass() + " finished executing."); - - } catch (Exception e) - { - operationLog.error("Sync failed: ", e); - sendErrorEmail(config, "Synchronization failed"); - } - } - } - - private Date getLastSyncTimeStamp(File lastSyncTimestampFile) throws ParseException - { - if (lastSyncTimestampFile.exists()) - { - String timeStr = FileUtilities.loadToString(lastSyncTimestampFile).trim(); - return formatter.parse(timeStr); - } - else - { - return new Date(0L); - } - } - - private Set<String> getDataSetCodesFromNotSyncedDataSetsFile(String fileName, ILineFilter linefilter) - { - File notSyncedDataSetsFile = new File(fileName); - if (notSyncedDataSetsFile.exists()) - { - List<String> list = FileUtilities.loadToStringList(notSyncedDataSetsFile, linefilter); - return new LinkedHashSet<String>(list); - } - else - { - return new LinkedHashSet<String>(); - } - } - - private Set<String> getNotSyncedDataSetCodes(String fileName) - { - return getDataSetCodesFromNotSyncedDataSetsFile(fileName, ExcludeEmptyAndCommentLineFilter.INSTANCE); - } - - private Set<String> getBlackListedDataSetCodes(String fileName) - { - return getDataSetCodesFromNotSyncedDataSetsFile(fileName, new ILineFilter() - { - @Override - public <T> boolean acceptLine(ILine<T> line) - { - assert line != null : "Unspecified line"; - final String trimmed = line.getText().trim(); - return trimmed.length() > 0 && trimmed.startsWith("#") == true; - } - }); - } - - private void sendErrorEmail(SyncConfig config, String subject) - { - if (config.getLogFilePath() != null) - { - // send the operation log as attachment - DataSource dataSource = createDataSource(config.getLogFilePath()); // /Users/gakin/Documents/sync.log - for (EMailAddress recipient : config.getEmailAddresses()) - { - mailClient.sendEmailMessageWithAttachment(subject, - "See the attached file for details.", - "", new DataHandler( - dataSource), null, null, recipient); - } - } - else - { - for (EMailAddress recipient : config.getEmailAddresses()) - { - mailClient.sendEmailMessage(subject, - "See the data store server log for details.", null, null, recipient); - } - } - } - - private DataSource createDataSource(final String filePath) - { - try - { - return new ByteArrayDataSource(new FileInputStream(filePath), "text/plain"); - } catch (IOException ex) - { - throw CheckedExceptionTunnel.wrapIfNecessary(ex); - } - } - - private void saveSyncTimestamp(File newLastSyncTimeStampFile, File lastSyncTimestampFile) - { - newLastSyncTimeStampFile.renameTo(lastSyncTimestampFile); - } -} diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/config/BasicAuthCredentials.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/config/BasicAuthCredentials.java deleted file mode 100644 index 396c88fea6e4fcd39d77a970074adc11be2221f8..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/config/BasicAuthCredentials.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2016 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.harvester.config; - -/** - * - * - * @author Ganime Betul Akin - */ -public class BasicAuthCredentials -{ - private String realm; - - private String user; - - private String password; - - public BasicAuthCredentials(String realm, String user, String pass) - { - this.realm = realm; - this.user = user; - this.password = pass; - } - - public String getRealm() - { - return realm; - } - - public void setRealm(String realm) - { - this.realm = realm; - } - - public String getUser() - { - return user; - } - - public void setUser(String user) - { - this.user = user; - } - - public String getPassword() - { - return password; - } - - public void setPassword(String pass) - { - this.password = pass; - } -} diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/config/ConfigReader.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/config/ConfigReader.java deleted file mode 100644 index 84be30be2d81974cce7edb7458fdeaffe8052c99..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/config/ConfigReader.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright 2016 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.harvester.config; - -/** - * - * - * @author Ganime Betul Akin - */ -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; - -public class ConfigReader -{ - - private static final String IGNORE_LINE_CHAR = "#"; - - private Pattern sectionRegex = Pattern.compile("\\s*\\[([^]]*)\\]\\s*"); - - private Pattern keyValueRegex = Pattern.compile("\\s*([^=]*)=(.*)"); - - private Map<String, Map<String, String>> entries = new LinkedHashMap<>(); - - public ConfigReader(String path) throws IOException - { - load(path); - } - - public ConfigReader(File file) throws IOException - { - loadFile(file); - } - - public static void main(String[] args) - { - ConfigReader reader; - try - { - reader = new ConfigReader("/Users/gakin/Documents/workspace_openbis_trunk/datastore_server/harvester.ini"); - for (int i = 0; i < reader.getSectionCount(); i++) - { - System.out.println(reader.getSection(i)); - } - - } catch (IOException e) - { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - public int getSectionCount() - { - return entries.keySet().size(); - } - - public String getSection(int index) - { - if (index > getSectionCount()) - { - throw new RuntimeException("Section with index " + index + " does not exist."); - } - return entries.keySet().toArray(new String[entries.keySet().size()])[index]; - } - - public boolean sectionExists(String name) - { - Map<String, String> kvMap = entries.get(name); - if (kvMap == null) - { - return false; - } - return true; - } - - public void loadFile(File file) throws IOException - { - try (BufferedReader br = new BufferedReader(new FileReader(file))) - { - String line; - String section = null; - while ((line = br.readLine()) != null) - { - Matcher m = sectionRegex.matcher(line); - if (m.matches()) - { - section = m.group(1).trim(); - } - else if (section != null) - { - m = keyValueRegex.matcher(line); - if (m.matches() && line.startsWith(IGNORE_LINE_CHAR) == false) - { - String key = m.group(1).trim(); - String value = m.group(2).trim(); - Map<String, String> map = entries.get(section); - if (map == null) - { - entries.put(section, map = new HashMap<>()); - } - map.put(key, value); - } - } - } - } - } - - public void load(String path) throws IOException - { - loadFile(new File(path)); - } - - public String getString(String section, String key, String defaultvalue, boolean mandatory) - { - String val = getValue(section, key); - if (val == null) - { - if (mandatory) - { - throw new ConfigurationFailureException("Property '" + key + "' in section '" + section + "' is mandatory."); - } - return defaultvalue; - } - return val; - } - - private String getValue(String section, String key) throws ConfigurationFailureException - { - Map<String, String> map = entries.get(section); - if (map == null) - { - throw new ConfigurationFailureException("Section '" + section + " does not exist."); - } - String val = map.get(key); - if (val == null) - { - return null; - } - if (val.trim().equals("") == true) - { - return null; - } - return val; - } - - public int getInt(String section, String key, int defaultvalue, boolean mandatory) - { - String val = getValue(section, key); - if (val == null) - { - if (mandatory) - { - throw new ConfigurationFailureException("Property '" + key + "' in section '" + section + "' is mandatory."); - } - return defaultvalue; - } - return Integer.parseInt(val); - } - - public double getDouble(String section, String key, double defaultvalue, boolean mandatory) - { - String val = getValue(section, key); - if (val == null) - { - if (mandatory) - { - throw new ConfigurationFailureException("Property '" + key + "' in section '" + section + "' is mandatory."); - } - return defaultvalue; - } - return Double.parseDouble(val); - } -} \ No newline at end of file diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/config/SyncConfig.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/config/SyncConfig.java deleted file mode 100644 index 154c762a75e19823fc2fbb5cf207d3d3ccb8ea2e..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/config/SyncConfig.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2016 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.harvester.config; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -import ch.systemsx.cisd.common.mail.EMailAddress; - -/** - * - * - * @author Ganime Betul Akin - */ -public class SyncConfig -{ - private String dataSourceURI; - - public String getDataSourceURI() - { - return dataSourceURI; - } - - public void setDataSourceURI(String dataSourceURI) - { - this.dataSourceURI = dataSourceURI; - } - - public String getDataSourceOpenbisURL() - { - return dataSourceOpenbisURL; - } - - public void setDataSourceOpenbisURL(String dataSourceOpenbisURL) - { - this.dataSourceOpenbisURL = dataSourceOpenbisURL; - } - - public String getDataSourceDSSURL() - { - return dataSourceDSSURL; - } - - public void setDataSourceDSSURL(String dataSourceDSSURL) - { - this.dataSourceDSSURL = dataSourceDSSURL; - } - - public String getLastSyncTimestampFileName() - { - return lastSyncTimestampFileName; - } - - public void setLastSyncTimestampFileName(String lastSyncTimestampFileName) - { - this.lastSyncTimestampFileName = lastSyncTimestampFileName; - } - - public String getNotSyncedDataSetsFileName() - { - return notSyncedDataSetsFileName; - } - - public void setNotSyncedDataSetsFileName(String notSyncedDataSetsFileName) - { - this.notSyncedDataSetsFileName = notSyncedDataSetsFileName; - } - - public String getDataSourceAlias() - { - return dataSourceAlias; - } - - public void setDataSourceAlias(String dataSourceAlias) - { - this.dataSourceAlias = dataSourceAlias; - } - - public List<String> getDataSourceSpaces() - { - return dataSourceSpaces; - } - - public void setDataSourceSpaces(String dataSourceSpaces) - { - if (dataSourceSpaces == null) - { - return; - } - for (String token : dataSourceSpaces.split(SEPARATOR)) - { - this.dataSourceSpaces.add(token.trim()); - } - } - - public List<String> getHarvesterSpaces() - { - return harvesterSpaces; - } - - public void setHarvesterSpaces(String harvesterSpaces) - { - if (harvesterSpaces == null) - { - return; - } - for (String token : harvesterSpaces.split(SEPARATOR)) - { - this.harvesterSpaces.add(token.trim()); - } - } - - public String getHarvesterTempDir() - { - return harvesterTempDir; - } - - public void setHarvesterTempDir(String harvesterTempDir) - { - this.harvesterTempDir = harvesterTempDir; - } - - public void printConfig() - { - for (Field field : this.getClass().getDeclaredFields()) - { - field.setAccessible(true); - String name = field.getName(); - Object value; - try - { - value = field.get(this); - System.out.printf("%s : %s%n", name, value); - } catch (IllegalArgumentException e) - { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IllegalAccessException e) - { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - - private BasicAuthCredentials auth; - - private String dataSourceOpenbisURL; - - private String dataSourceDSSURL; - - private String lastSyncTimestampFileName; - - private String notSyncedDataSetsFileName; - - private String dataSourceAlias; - - private List<String> dataSourceSpaces = new ArrayList<>(); - - private List<String> harvesterSpaces = new ArrayList<>(); - - private String harvesterTempDir; - - private List<EMailAddress> emailAddresses = new ArrayList<>(); - - private String logFilePath; - - private static final String SEPARATOR = ","; - - private HashMap<String, String> spaceMappings = new HashMap<String, String>(); - - public HashMap<String, String> getSpaceMappings() - { - return spaceMappings; - } - - public String getLogFilePath() - { - return logFilePath; - } - - public void setLogFilePath(String logFilePath) - { - this.logFilePath = logFilePath; - } - - public List<EMailAddress> getEmailAddresses() - { - return emailAddresses; - } - - public void setEmailAddresses(String emailAddresses) - { - for (String token : emailAddresses.split(SEPARATOR)) - { - this.emailAddresses.add(new EMailAddress(token.trim())); - } - } - - public void setAuthCredentials(String realm, String user, String pass) - { - this.auth = new BasicAuthCredentials(realm, user, pass); - } - - public BasicAuthCredentials getAuthenticationCredentials() - { - return auth; - } - - public String getUser() - { - return this.auth.getUser(); - } - - public String getPassword() - { - return this.auth.getPassword(); - } -} diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/config/SynchronizationConfigReader.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/config/SynchronizationConfigReader.java deleted file mode 100644 index 06cb146dc810a1788b33ba874d3182e841fa74a4..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/config/SynchronizationConfigReader.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2016 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.harvester.config; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Pattern; - -import org.apache.log4j.DailyRollingFileAppender; -import org.apache.log4j.Logger; -import org.apache.log4j.PatternLayout; - -import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; -import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Space; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier; - -/** - * - * - * @author Ganime Betul Akin - */ -public class SynchronizationConfigReader -{ - private static final String DEFAULT_HARVESTER_TEMP_DIR = "targets/store"; - - private static final String DATA_SOURCE_URL_PROPERTY_NAME = "resource-list-url"; - - private static final String DATA_SOURCE_OPENBIS_URL_PROPERTY_NAME = "data-source-openbis-url"; - - private static final String DATA_SOURCE_DSS_URL_PROPERTY_NAME = "data-source-dss-url"; - - private static final String DATA_SOURCE_SPACES_PROPERTY_NAME = "data-source-spaces"; - - private static final String DATA_SOURCE_ALIAS_PROPERTY_NAME = "data-source-alias"; - - private static final String DATA_SOURCE_AUTH_REALM_PROPERTY_NAME = "data-source-auth-realm"; - - private static final String DATA_SOURCE_AUTH_USER_PROPERTY_NAME = "data-source-auth-user"; - - private static final String DATA_SOURCE_AUTH_PASS_PROPERTY_NAME = "data-source-auth-pass"; - - private static final String HARVESTER_SPACES_PROPERTY_NAME = "harvester-spaces"; - - private static final String HARVESTER_TEMP_DIR_PROPERTY_NAME = "harvester-tmp-dir"; - - private static final String DEFAULT_LOG_FILE_NAME = "../../syncronization.log"; - - private static final String HARVESTER_LAST_SYNC_TIMESTAMP_FILE_PROPERTY_NAME = "last-sync-timestamp-file"; - - private static final String HARVESTER_NOT_SYNCED_DATA_SETS_FILE_NAME = "not-synced-data-sets-file"; - - private static final String EMAIL_ADDRESSES_PROPERTY_NAME = "email-addresses"; - - private String defaultLastSyncTimestampFileName = "last-sync-timestamp-file_{alias}.txt"; - - private String defaultNotSyncedDataSetsFileName = "not-synced-datasets_{alias}.txt"; - - private static final String LOG_FILE_PROPERTY_NAME = "log-file"; - - List<SyncConfig> configs = new ArrayList<>(); - - public List<SyncConfig> readConfiguration(File harvesterConfigFile, Logger logger) throws IOException - { - ConfigReader reader = new ConfigReader(harvesterConfigFile); - int sectionCount = reader.getSectionCount(); - for (int i = 0; i < sectionCount; i++) - { - String section = reader.getSection(i); - SyncConfig config = new SyncConfig(); - config.setEmailAddresses(reader.getString(section, EMAIL_ADDRESSES_PROPERTY_NAME, null, true)); - config.setLogFilePath(reader.getString(section, LOG_FILE_PROPERTY_NAME, DEFAULT_LOG_FILE_NAME, false)); - if (config.getLogFilePath() != null) - { - configureFileAppender(config, logger); - } - - config.setDataSourceAlias(reader.getString(section, DATA_SOURCE_ALIAS_PROPERTY_NAME, null, true)); - config.setDataSourceURI(reader.getString(section, DATA_SOURCE_URL_PROPERTY_NAME, null, true)); - config.setDataSourceOpenbisURL(reader.getString(section, DATA_SOURCE_OPENBIS_URL_PROPERTY_NAME, null, true)); - config.setDataSourceDSSURL(reader.getString(section, DATA_SOURCE_DSS_URL_PROPERTY_NAME, null, true)); - String realm = reader.getString(section, DATA_SOURCE_AUTH_REALM_PROPERTY_NAME, null, true); - String user = reader.getString(section, DATA_SOURCE_AUTH_USER_PROPERTY_NAME, null, true); - String pass = reader.getString(section, DATA_SOURCE_AUTH_PASS_PROPERTY_NAME, null, true); - config.setAuthCredentials(realm, user, pass); - - String dsSpaces = reader.getString(section, DATA_SOURCE_SPACES_PROPERTY_NAME, null, false); - if (dsSpaces != null) - { - config.setDataSourceSpaces(dsSpaces); - } - String hrvSpaces = reader.getString(section, HARVESTER_SPACES_PROPERTY_NAME, null, false); - if (hrvSpaces != null) - { - config.setHarvesterSpaces(hrvSpaces); - } - if (dsSpaces != null && hrvSpaces != null) - { - createDataSourceToHarvesterSpaceMappings(config); - } - - config.setHarvesterTempDir(reader.getString(section, HARVESTER_TEMP_DIR_PROPERTY_NAME, DEFAULT_HARVESTER_TEMP_DIR, false)); - - defaultLastSyncTimestampFileName = defaultLastSyncTimestampFileName.replaceFirst(Pattern.quote("{alias}"), config.getDataSourceAlias()); - config.setLastSyncTimestampFileName( - reader.getString(section, HARVESTER_LAST_SYNC_TIMESTAMP_FILE_PROPERTY_NAME, defaultLastSyncTimestampFileName, false)); - - defaultNotSyncedDataSetsFileName = defaultNotSyncedDataSetsFileName.replaceFirst(Pattern.quote("{alias}"), config.getDataSourceAlias()); - config.setNotSyncedDataSetsFileName( - reader.getString(section, HARVESTER_NOT_SYNCED_DATA_SETS_FILE_NAME, defaultNotSyncedDataSetsFileName, false)); - configs.add(config); - } - return configs; - } - - private void configureFileAppender(SyncConfig config, Logger logger) - { - DailyRollingFileAppender console = new DailyRollingFileAppender(); // create appender - // configure the appender - console.setName("bdfile"); - String PATTERN = "%d %-5p [%t] %c - %m%n"; - console.setLayout(new PatternLayout(PATTERN)); - // console.setThreshold(Level.FATAL); - console.setAppend(false); - console.setFile(config.getLogFilePath()); - console.activateOptions(); - // add appender to any Logger (here is root) - logger.addAppender(console); - logger.setAdditivity(false); - } - - private void createDataSourceToHarvesterSpaceMappings(SyncConfig config) - { - List<String> dataSourceSpaceList = config.getDataSourceSpaces(); - List<String> harvesterSpaceList = config.getHarvesterSpaces(); - if (dataSourceSpaceList.size() != harvesterSpaceList.size()) - { - throw new ConfigurationFailureException("Please specify a harvester space for each data source space."); - } - for (int i = 0; i < dataSourceSpaceList.size(); i++) - { - String harvesterSpace = harvesterSpaceList.get(i); - Space destSpace = ServiceProvider.getOpenBISService().tryGetSpace(new SpaceIdentifier(harvesterSpace)); - if (destSpace == null) - { - throw new ConfigurationFailureException("Space " + harvesterSpace + " does not exist"); - } - config.getSpaceMappings().put(dataSourceSpaceList.get(i), harvesterSpace); - } - } -} diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/DSSFileUtils.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/DSSFileUtils.java deleted file mode 100644 index 73f440854485db7728531cd2c1031f7b6171e014..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/DSSFileUtils.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2016 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.harvester.synchronizer; - -import java.io.InputStream; -import java.util.List; - -import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.SearchResult; -import ch.ethz.sis.openbis.generic.dssapi.v3.IDataStoreServerApi; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.DataSetFile; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.download.DataSetFileDownloadOptions; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.fetchoptions.DataSetFileFetchOptions; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.id.IDataSetFileId; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.search.DataSetFileSearchCriteria; -import ch.systemsx.cisd.common.spring.HttpInvokerUtils; -import ch.systemsx.cisd.common.ssl.SslCertificateHelper; - -/** - * - * - * @author Ganime Betul Akin - */ -public class DSSFileUtils -{ - public static final int TIMEOUT = 100000; - - private final IDataStoreServerApi dss; - private final IApplicationServerApi as; - - public static DSSFileUtils create(String asUrl, String dssUrl) - { - return new DSSFileUtils(asUrl, dssUrl, TIMEOUT); - } - - private DSSFileUtils (String asUrl, String dssUrl, int timeout) - { - SslCertificateHelper.trustAnyCertificate(asUrl); - SslCertificateHelper.trustAnyCertificate(dssUrl); - - this.dss = HttpInvokerUtils.createStreamSupportingServiceStub(IDataStoreServerApi.class, dssUrl + IDataStoreServerApi.SERVICE_URL, timeout); - this.as = HttpInvokerUtils.createServiceStub(IApplicationServerApi.class, asUrl + IApplicationServerApi.SERVICE_URL, timeout); - } - - public SearchResult<DataSetFile> searchFiles(String sessionToken, DataSetFileSearchCriteria criteria, DataSetFileFetchOptions dsFileFetchOptions) - { - return dss.searchFiles(sessionToken, criteria, dsFileFetchOptions); - } - - public SearchResult<DataSetFile> searchWithDataSetCode(String sessionToken, String dataSetCode, DataSetFileFetchOptions dsFileFetchOptions) - { - DataSetFileSearchCriteria criteria = new DataSetFileSearchCriteria(); - criteria.withDataSet().withCode().thatEquals(dataSetCode); - return searchFiles(sessionToken, criteria, dsFileFetchOptions); - } - - public InputStream downloadFiles(String sessionToken, List<IDataSetFileId> fileIds, DataSetFileDownloadOptions options) - { - return dss.downloadFiles(sessionToken, fileIds, options); - } - - public String login(String loginUser, String loginPass) - { - return as.login(loginUser, loginPass); - } -} diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/DataSetRegistrationIngestionService.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/DataSetRegistrationIngestionService.java deleted file mode 100644 index 42848742a355cdf409c4af86966e1bd0fe38157d..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/DataSetRegistrationIngestionService.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 2016 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.harvester.synchronizer; - -import java.io.File; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import org.apache.log4j.Logger; - -import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.SearchResult; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.DataSetFile; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.download.DataSetFileDownload; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.download.DataSetFileDownloadOptions; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.download.DataSetFileDownloadReader; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.fetchoptions.DataSetFileFetchOptions; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.id.DataSetFilePermId; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.id.IDataSetFileId; -import ch.systemsx.cisd.common.io.IOUtilities; -import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSet; -import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSetRegistrationTransactionV2; -import ch.systemsx.cisd.etlserver.registrator.api.v2.IDataSetUpdatable; -import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.IngestionService; -import ch.systemsx.cisd.openbis.dss.generic.shared.DataSetProcessingContext; -import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.IExperimentImmutable; -import ch.systemsx.cisd.openbis.dss.generic.shared.api.internal.v2.ISampleImmutable; -import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel; -import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData; -import ch.systemsx.cisd.openbis.generic.shared.dto.NewProperty; - -class DataSetRegistrationIngestionService extends IngestionService<DataSetInformation> -{ - private static final long serialVersionUID = 1L; - - private List<String> notSyncedDataSetCodes; - - private final NewExternalData dataSet; - - private final String loginUser; - - private final String loginPass; - - private final String asUrl; - - private final String dssUrl; - - private final String harvesterTempDir; - - private final Logger log; - - public DataSetRegistrationIngestionService(Properties properties, File storeRoot, List<String> notSyncedDataSetCodes, NewExternalData ds, - Logger operationLog) - { - super(properties, storeRoot); - this.notSyncedDataSetCodes = notSyncedDataSetCodes; - this.dataSet = ds; - this.loginUser = properties.getProperty("user"); - this.loginPass = properties.getProperty("pass"); - this.asUrl = properties.getProperty("as-url"); - this.dssUrl = properties.getProperty("dss-url"); - this.harvesterTempDir = properties.getProperty("harvester-temp-dir"); - this.log = operationLog; - } - - @Override - protected TableModel process(IDataSetRegistrationTransactionV2 transaction, Map<String, Object> parameters, DataSetProcessingContext context) - { - String dataSetCode = dataSet.getCode(); - ISampleImmutable sample = null; - if (dataSet.getSampleIdentifierOrNull() != null) - { - sample = transaction.getSampleForUpdate(dataSet.getSampleIdentifierOrNull().toString()); - } - IExperimentImmutable experiment = null; - if (dataSet.getExperimentIdentifierOrNull() != null) - { - experiment = transaction.getExperimentForUpdate(dataSet.getExperimentIdentifierOrNull().toString()); - } - - List<NewProperty> dataSetProperties = dataSet.getDataSetProperties(); - - IDataSetUpdatable dataSetForUpdate = transaction.getDataSetForUpdate(dataSetCode); - if (dataSetForUpdate == null) - { - // REGISTER NEW DATA SET after downloading the data set files - File storeRoot = transaction.getGlobalState().getStoreRootDir(); - File temp = new File(storeRoot, this.harvesterTempDir); - temp.mkdirs(); - File dir = new File(temp, dataSetCode); - dir.mkdirs(); - - try - { - downloadDataSetFiles(dir, dataSetCode); - } catch (Exception e) - { - return errorTableModel(parameters, e); - } - - IDataSet ds = transaction.createNewDataSet(dataSet.getDataSetType().getCode(), dataSet.getCode()); - ds.setSample(sample); - ds.setExperiment(experiment); - for (NewProperty newProperty : dataSetProperties) - { - ds.setPropertyValue(newProperty.getPropertyCode(), newProperty.getValue()); - } - - for (File f : dir.listFiles()) - { - transaction.moveFile(f.getAbsolutePath(), ds); - } - } - else - { - // UPDATE data set meta data excluding the container/contained relationships - dataSetForUpdate.setSample(sample); - dataSetForUpdate.setExperiment(experiment); - dataSetForUpdate.setParentDatasets(dataSet.getParentDataSetCodes()); - for (NewProperty newProperty : dataSetProperties) - { - dataSetForUpdate.setPropertyValue(newProperty.getPropertyCode(), newProperty.getValue()); - } - } - return null; - } - - class FileDetails - { - final int crc32checksum; - - final long fileLength; - - public FileDetails(int crc32checksum, long fileLength) - { - super(); - this.crc32checksum = crc32checksum; - this.fileLength = fileLength; - } - - public int getCrc32checksum() - { - return crc32checksum; - } - - public long getFileLength() - { - return fileLength; - } - } - - private void downloadDataSetFiles(File dir, String dataSetCode) throws Exception - { - DSSFileUtils dssFileUtils = DSSFileUtils.create(asUrl, dssUrl); - String sessionToken = dssFileUtils.login(loginUser, loginPass); - DataSetFileFetchOptions dsFileFetchOptions = new DataSetFileFetchOptions(); - SearchResult<DataSetFile> result = dssFileUtils.searchWithDataSetCode(sessionToken, dataSetCode, dsFileFetchOptions); - List<DataSetFile> files = result.getObjects(); - - List<IDataSetFileId> fileIds = new LinkedList<IDataSetFileId>(); - Map<DataSetFilePermId, FileDetails> fileDetailsMap = new HashMap<DataSetFilePermId, FileDetails>(); - for (DataSetFile f : files) - { - fileIds.add(f.getPermId()); - fileDetailsMap.put(f.getPermId(), new FileDetails(f.getChecksumCRC32(), f.getFileLength())); - } - // Download the files & print the contents - DataSetFileDownloadOptions options = new DataSetFileDownloadOptions(); - options.setRecursive(false); - InputStream stream = dssFileUtils.downloadFiles(sessionToken, fileIds, options); - DataSetFileDownloadReader reader = new DataSetFileDownloadReader(stream); - DataSetFileDownload fileDownload = null; - while ((fileDownload = reader.read()) != null) - { - DataSetFile orgFile = fileDownload.getDataSetFile(); - if (orgFile.getPath().equals("")) - continue; - // if (dsFile.getPath().equals("original")) - // continue; - String filePath = orgFile.getPath();// .substring("original/".length()); - File output = new File(dir.getAbsolutePath(), filePath); - if (orgFile.isDirectory()) - { - output.mkdirs(); - } - else - { - DataSetFilePermId filePermId = orgFile.getPermId(); - FileDetails fileDetails = fileDetailsMap.get(filePermId); - - // System.out.println("Downloaded " + orgFile.getPath() + " " - // + MemorySizeFormatter.format(orgFile.getFileLength())); - - Path path = Paths.get(dir.getAbsolutePath(), filePath); - InputStream inputStream = fileDownload.getInputStream(); - OutputStream outputStream = Files.newOutputStream(path); - int checksumCRC32 = IOUtilities.copyAndGetChecksumCRC32(inputStream, outputStream); - File copiedFile = new File(path.normalize().toString()); - if (checksumCRC32 != fileDetails.getCrc32checksum() - || copiedFile.length() != fileDetails.getFileLength()) - { - throw new RuntimeException("Crc32 or file length does not match for " + orgFile.getPath() + " calculated:" + checksumCRC32 - + " expected:" - + fileDetails.getCrc32checksum()); - } - } - } - } -} \ No newline at end of file diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/EntitySynchronizer.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/EntitySynchronizer.java deleted file mode 100644 index 7b634a475e4153bcc6a33ca9c1774783b4f6adf6..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/EntitySynchronizer.java +++ /dev/null @@ -1,1102 +0,0 @@ -/* - * Copyright 2016 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.harvester.synchronizer; - -import java.io.File; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; - -import org.apache.commons.codec.binary.Hex; -import org.apache.commons.io.FileUtils; -import org.apache.commons.lang.ArrayUtils; -import org.apache.log4j.Logger; -import org.w3c.dom.Document; - -import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.SearchResult; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSetKind; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.delete.DataSetDeletionOptions; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.deletion.id.IDeletionId; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.delete.ExperimentDeletionOptions; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentPermId; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.delete.MaterialDeletionOptions; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.id.MaterialPermId; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.delete.ProjectDeletionOptions; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.id.ProjectPermId; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.delete.SampleDeletionOptions; -import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SamplePermId; -import ch.ethz.sis.openbis.generic.dssapi.v3.IDataStoreServerApi; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.DataSetFile; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.fetchoptions.DataSetFileFetchOptions; -import ch.ethz.sis.openbis.generic.dssapi.v3.dto.datasetfile.search.DataSetFileSearchCriteria; -import ch.ethz.sis.openbis.generic.server.EntityRetriever; -import ch.ethz.sis.openbis.generic.server.dss.ServiceFinderUtils; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.config.SyncConfig; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.ResourceListParserData.Connection; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.ResourceListParserData.DataSetWithConnections; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.ResourceListParserData.ExperimentWithConnections; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.ResourceListParserData.MaterialWithLastModificationDate; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.ResourceListParserData.ProjectWithConnections; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.ResourceListParserData.SampleWithConnections; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.datasourceconnector.DataSourceConnector; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.datasourceconnector.IDataSourceConnector; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.translator.INameTranslator; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.translator.PrefixBasedNameTranslator; -import ch.ethz.sis.openbis.generic.shared.entitygraph.EntityGraph; -import ch.ethz.sis.openbis.generic.shared.entitygraph.Node; -import ch.systemsx.cisd.common.concurrent.ITaskExecutor; -import ch.systemsx.cisd.common.concurrent.ParallelizedExecutor; -import ch.systemsx.cisd.common.exceptions.Status; -import ch.systemsx.cisd.common.filesystem.FileUtilities; -import ch.systemsx.cisd.common.logging.Log4jSimpleLogger; -import ch.systemsx.cisd.etlserver.registrator.api.v1.impl.ConversionUtils; -import ch.systemsx.cisd.openbis.dss.generic.shared.DataSetDirectoryProvider; -import ch.systemsx.cisd.openbis.dss.generic.shared.DataSetProcessingContext; -import ch.systemsx.cisd.openbis.dss.generic.shared.IConfigProvider; -import ch.systemsx.cisd.openbis.dss.generic.shared.IDataSetDirectoryProvider; -import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; -import ch.systemsx.cisd.openbis.dss.generic.shared.IShareIdManager; -import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; -import ch.systemsx.cisd.openbis.dss.generic.shared.utils.SegmentedStoreUtils; -import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl.EncapsulatedCommonServer; -import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl.MasterDataRegistrationException; -import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl.MasterDataRegistrationTransaction; -import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl.MasterDataTransactionErrors; -import ch.systemsx.cisd.openbis.generic.shared.basic.TechId; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AbstractExternalData; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListSampleCriteria; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Material; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialIdentifier; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewAttachment; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewExperiment; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewMaterialWithType; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewProject; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSpace; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PhysicalDataSet; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Project; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Space; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModelColumnHeader; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.PropertyBuilder; -import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationResult; -import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetBatchUpdatesDTO; -import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentUpdatesDTO; -import ch.systemsx.cisd.openbis.generic.shared.dto.MaterialUpdateDTO; -import ch.systemsx.cisd.openbis.generic.shared.dto.NewContainerDataSet; -import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData; -import ch.systemsx.cisd.openbis.generic.shared.dto.NewProperty; -import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectUpdatesDTO; -import ch.systemsx.cisd.openbis.generic.shared.dto.SampleUpdatesDTO; -import ch.systemsx.cisd.openbis.generic.shared.dto.builders.AtomicEntityOperationDetailsBuilder; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ProjectIdentifier; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ProjectIdentifierFactory; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier; - -/** - * @author Ganime Betul Akin - */ -public class EntitySynchronizer -{ - private final String dataStoreCode; - - private final File storeRoot; - - private final IEncapsulatedOpenBISService service; - - private final DataSetProcessingContext context; - - private final Date lastSyncTimestamp; - - private final Set<String> dataSetsCodesToRetry; - - private final SyncConfig config; - - private final Logger operationLog; - - private final Set<String> blackListedDataSetCodes; - - private final MasterDataRegistrationTransaction masterDataRegistrationTransaction; - - public EntitySynchronizer(IEncapsulatedOpenBISService service, String dataStoreCode, File storeRoot, Date lastSyncTimestamp, - Set<String> dataSetsCodesToRetry, Set<String> blackListedDataSetCodes, DataSetProcessingContext context, - SyncConfig config, Logger operationLog) - { - this.service = service; - this.dataStoreCode = dataStoreCode; - this.storeRoot = storeRoot; - this.lastSyncTimestamp = lastSyncTimestamp; - this.dataSetsCodesToRetry = dataSetsCodesToRetry; - this.blackListedDataSetCodes = blackListedDataSetCodes; - this.context = context; - this.config = config; - this.operationLog = operationLog; - this.masterDataRegistrationTransaction = getMasterDataRegistrationTransaction(); - } - - public Date syncronizeEntities() throws Exception - { - DataSourceConnector dataSourceConnector = new DataSourceConnector(config.getDataSourceURI(), config.getAuthenticationCredentials()); - return syncronizeEntities(dataSourceConnector); - } - - public Date syncronizeEntities(IDataSourceConnector dataSourceConnector) throws Exception - { - // retrieve the document from the data source - operationLog.info("Retrieving the resource list.."); - Document doc = dataSourceConnector.getResourceListAsXMLDoc(Arrays.asList(ArrayUtils.EMPTY_STRING_ARRAY)); - - // 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"); - String dataSourcePrefix = config.getDataSourceAlias(); - INameTranslator nameTranslator = null; - if (dataSourcePrefix != null && dataSourcePrefix.trim().equals("") == false) - { - nameTranslator = new PrefixBasedNameTranslator(dataSourcePrefix); - } - - ResourceListParser parser = ResourceListParser.create(nameTranslator, dataStoreCode, masterDataRegistrationTransaction); // , - // lastSyncTimestamp - ResourceListParserData data = parser.parseResourceListDocument(doc); - - processDeletions(data); - - operationLog.info("registering master data"); - // registerMasterData(); - - AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder(); - - for (String spaceCode : data.getHarvesterSpaceList()) - { - Space space = service.tryGetSpace(new SpaceIdentifier(spaceCode)); - if (space == null) - { - builder.space(new NewSpace(spaceCode, "Synchronized from: " + config.getDataSourceURI(), null)); - } - } - - processMetaData(data, builder); - - operationLog.info("Registering meta data..."); - AtomicEntityOperationResult operationResult = service.performEntityOperations(builder.getDetails()); - operationLog.info("entity operation result: " + operationResult); - - // register physical data sets without any hierarchy - // Note that container/component and parent/child relationships are established post-reg. - // setParentDataSetsOnTheChildren(data); - Map<String, DataSetWithConnections> physicalDSMap = - data.filterPhysicalDataSetsByLastModificationDate(lastSyncTimestamp, dataSetsCodesToRetry); - operationLog.info("Registering data sets..."); - List<String> notRegisteredDataSets = registerPhysicalDataSets(physicalDSMap); - operationLog.info((physicalDSMap.keySet().size() - notRegisteredDataSets.size()) + " data set(s) have been successfully registered. " - + notRegisteredDataSets.size() - + " data set(s) FAILED to register "); - - // link physical data sets registered above to container data sets - // and set parent/child relationships - operationLog.info("start linking/un-linking container and component data sets"); - establishDataSetRelationships(data.getDataSetsToProcess(), notRegisteredDataSets, physicalDSMap); - - return data.getResourceListTimestamp(); - } - - private void establishDataSetRelationships(Map<String, DataSetWithConnections> dataSetsToProcess, - List<String> notRegisteredDataSets, Map<String, DataSetWithConnections> physicalDSMap) - { - // set parent and container data set codes before everything else - // container and physical data sets can both be parents/children of each other - AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder(); - Map<String, NewExternalData> datasetsToUpdate = new HashMap<String, NewExternalData>(); - Map<String, Set<String>> dsToParents = new HashMap<String, Set<String>>(); - Map<String, Set<String>> dsToContained = new HashMap<String, Set<String>>(); - for (DataSetWithConnections dsWithConn : dataSetsToProcess.values()) - { - for (Connection conn : dsWithConn.getConnections()) - { - NewExternalData dataSet = dsWithConn.getDataSet(); - if (dataSetsToProcess.containsKey(conn.getToPermId()) && conn.getType().equals("Child")) - { - if (notRegisteredDataSets.contains(dataSet.getCode()) == false) - { - NewExternalData childDataSet = dataSetsToProcess.get(conn.getToPermId()).getDataSet(); - List<String> parentDataSetCodes = childDataSet.getParentDataSetCodes(); - parentDataSetCodes.add(dataSet.getCode()); - dsToParents.put(childDataSet.getCode(), new HashSet<String>(parentDataSetCodes)); - } - } - else if (dataSetsToProcess.containsKey(conn.getToPermId()) && conn.getType().equals("Component")) - { - NewExternalData componentDataSet = dataSetsToProcess.get(conn.getToPermId()).getDataSet(); - if (notRegisteredDataSets.contains(componentDataSet.getCode()) == false) - { - NewContainerDataSet containerDataSet = (NewContainerDataSet) dataSet; - List<String> containedDataSetCodes = containerDataSet.getContainedDataSetCodes(); - containedDataSetCodes.add(componentDataSet.getCode()); - dsToContained.put(dataSet.getCode(), new HashSet<String>(containedDataSetCodes)); - } - } - } - } - // go through all the data sets, decide what needs to be updated - for (DataSetWithConnections dsWithConn : dataSetsToProcess.values()) - { - NewExternalData dataSet = (NewExternalData) dsWithConn.getDataSet(); - - if (dsWithConn.getLastModificationDate().after(lastSyncTimestamp) - || dataSetsCodesToRetry.contains(dataSet.getCode()) == true - || isParentModified(dsToParents, dataSet)) - { - if (physicalDSMap.containsKey(dataSet.getCode()) == false && service.tryGetDataSet(dataSet.getCode()) == null) - { - builder.dataSet(dataSet); - } - else - { - datasetsToUpdate.put(dataSet.getCode(), dataSet); - } - } - } - - // go thru to-be-updated DS list and establish/break relations - for (NewExternalData dataSet : datasetsToUpdate.values()) - { - // if the DS could not have been registered for some reason, - // skip this. - AbstractExternalData dsInHarvester = service.tryGetDataSet(dataSet.getCode()); - if (dsInHarvester == null) - { - continue; - } - DataSetBatchUpdatesDTO dsBatchUpdatesDTO = createDataSetBatchUpdateDTO(dataSet, dsInHarvester); - if (dataSet instanceof NewContainerDataSet) - { - NewContainerDataSet containerDS = (NewContainerDataSet) dataSet; - if (dsToContained.containsKey(containerDS.getCode())) - { - dsBatchUpdatesDTO.setModifiedContainedDatasetCodesOrNull(dsToContained.get(dataSet.getCode()).toArray(new - String[containerDS.getContainedDataSetCodes().size()])); - } - else - { - dsBatchUpdatesDTO.setModifiedContainedDatasetCodesOrNull(new String[0]); - } - dsBatchUpdatesDTO.getDetails().setContainerUpdateRequested(true); - } - if (dsToParents.containsKey(dataSet.getCode())) - { - dsBatchUpdatesDTO.setModifiedParentDatasetCodesOrNull(dsToParents.get(dataSet.getCode()).toArray( - new String[dataSet.getParentDataSetCodes().size()])); - // TODO should this always be true or should we flag the ones that require parent update. Same for container - } - else - { - dsBatchUpdatesDTO.setModifiedParentDatasetCodesOrNull(new String[0]); - } - dsBatchUpdatesDTO.getDetails().setParentsUpdateRequested(true); - SampleIdentifier sampleIdentifier = dataSet.getSampleIdentifierOrNull(); - if (sampleIdentifier != null) - { - Sample sampleWithExperiment = service.tryGetSampleWithExperiment(sampleIdentifier); - dsBatchUpdatesDTO.setSampleIdentifierOrNull(SampleIdentifierFactory.parse(sampleWithExperiment.getIdentifier())); - dsBatchUpdatesDTO.getDetails().setSampleUpdateRequested(true); - } - else - { - dsBatchUpdatesDTO.setSampleIdentifierOrNull(null); - dsBatchUpdatesDTO.getDetails().setSampleUpdateRequested(true); - } - - ExperimentIdentifier expIdentifier = dataSet.getExperimentIdentifierOrNull(); - if (expIdentifier != null) - { - Experiment experiment = service.tryGetExperiment(expIdentifier); - dsBatchUpdatesDTO.setExperimentIdentifierOrNull(ExperimentIdentifierFactory.parse(experiment.getIdentifier())); - dsBatchUpdatesDTO.getDetails().setExperimentUpdateRequested(true); - } - else - { - dsBatchUpdatesDTO.setExperimentIdentifierOrNull(null); - dsBatchUpdatesDTO.getDetails().setExperimentUpdateRequested(true); - } - builder.dataSetUpdate(dsBatchUpdatesDTO); - } - AtomicEntityOperationResult operationResult = service.performEntityOperations(builder.getDetails()); - operationLog.info("entity operation result: " + operationResult); - } - - private boolean isParentModified(Map<String, Set<String>> dsToParents, NewExternalData dataSet) - { - Set<String> parents = dsToParents.get(dataSet.getCode()); - if (parents == null) - { - return false; - } - for (String parentDSCode : parents) - { - if (dataSetsCodesToRetry.contains(parentDSCode)) - { - return true; - } - } - return false; - } - - private List<String> registerPhysicalDataSets(Map<String, DataSetWithConnections> physicalDSMap) throws IOException - { - List<DataSetWithConnections> dsList = new ArrayList<DataSetWithConnections>(physicalDSMap.values()); - List<String> notRegisteredDataSetCodes = Collections.synchronizedList(new ArrayList<String>()); - - // This parallelization is possible because each DS is registered without dependencies - // and the dependencies are established later on in the sync process. - ParallelizedExecutor.process(dsList, new DataSetRegistrationTaskExecutor(notRegisteredDataSetCodes), 0.5, 10, "register data sets", 0, false); - - // backup the current not synced data set codes file, delete the original file - saveNotSyncedDataSetsFile(notRegisteredDataSetCodes); - - return notRegisteredDataSetCodes; - } - - private void saveNotSyncedDataSetsFile(List<String> notRegisteredDataSetCodes) throws IOException - { - File notSyncedDataSetsFile = new File(config.getNotSyncedDataSetsFileName()); - if (notSyncedDataSetsFile.exists()) - { - backupAndResetNotSyncedDataSetsFile(notSyncedDataSetsFile); - } - - for (String dsCode : notRegisteredDataSetCodes) - { - FileUtilities.appendToFile(notSyncedDataSetsFile, dsCode, true); - } - // append the blacklisted codes to the end of the file - for (String dsCode : blackListedDataSetCodes) - { - FileUtilities.appendToFile(notSyncedDataSetsFile, dsCode, true); - } - } - - private void backupAndResetNotSyncedDataSetsFile(File notSyncedDataSetsFile) throws IOException - { - File backupLastSyncTimeStampFile = new File(config.getNotSyncedDataSetsFileName() + ".bk"); - FileUtils.copyFile(notSyncedDataSetsFile, backupLastSyncTimeStampFile); - FileUtils.writeStringToFile(notSyncedDataSetsFile, ""); - } - - private void processMetaData(ResourceListParserData data, AtomicEntityOperationDetailsBuilder builder) - { - processProjects(data, builder); - - processExperiments(data, builder); - - processSamples(data, builder); - - processMaterials(data, builder); - } - - private void registerMasterData() - { - masterDataRegistrationTransaction.commit(); - MasterDataTransactionErrors transactionErrors = masterDataRegistrationTransaction.getTransactionErrors(); - if (false == transactionErrors.getErrors().isEmpty()) - { - MasterDataRegistrationException masterDataRegistrationException = - new MasterDataRegistrationException("Master data synchronization finished with errors:", - Collections - .<MasterDataTransactionErrors> singletonList(transactionErrors)); - operationLog.info("Master data synchronizatio finished with errors"); - masterDataRegistrationException.logErrors(new Log4jSimpleLogger(operationLog)); - } - } - - private MasterDataRegistrationTransaction getMasterDataRegistrationTransaction() - { - String openBisServerUrl = ServiceProvider.getConfigProvider().getOpenBisServerUrl(); - String sessionToken = ServiceProvider.getOpenBISService().getSessionToken(); - EncapsulatedCommonServer encapsulatedCommonServer = ServiceFinderUtils.getEncapsulatedCommonServer(sessionToken, openBisServerUrl); - return new MasterDataRegistrationTransaction(encapsulatedCommonServer); - } - - private void processDeletions(ResourceListParserData data) throws NoSuchAlgorithmException, UnsupportedEncodingException - { - operationLog.info("Processing deletions"); - String sessionToken = ServiceProvider.getOpenBISService().getSessionToken(); - EntityRetriever entityRetriever = - EntityRetriever.createWithSessionToken(ServiceProvider.getV3ApplicationService(), sessionToken); - - Set<String> incomingProjectPermIds = data.getProjectsToProcess().keySet(); - Set<String> incomingExperimentPermIds = data.getExperimentsToProcess().keySet(); - Set<String> incomingSamplePermIds = data.getSamplesToProcess().keySet(); - Set<String> incomingDataSetCodes = data.getDataSetsToProcess().keySet(); - Set<String> incomingMaterialCodes = data.getMaterialsToProcess().keySet(); - - // find projects, experiments, samples and data sets to be deleted - List<ProjectPermId> projectPermIds = new ArrayList<ProjectPermId>(); - List<ExperimentPermId> experimentPermIds = new ArrayList<ExperimentPermId>(); - List<SamplePermId> samplePermIds = new ArrayList<SamplePermId>(); - List<DataSetPermId> dsPermIds = new ArrayList<DataSetPermId>(); - List<MaterialPermId> matPermIds = new ArrayList<MaterialPermId>(); - - Set<PhysicalDataSet> physicalDataSetsDelete = new HashSet<PhysicalDataSet>(); - // first find out the entities to be deleted - for (String harvesterSpaceId : data.getHarvesterSpaceList()) - { - EntityGraph<Node<?>> harvesterEntityGraph = entityRetriever.getEntityGraph(harvesterSpaceId); - List<Node<?>> entities = harvesterEntityGraph.getNodes(); - for (Node<?> entity : entities) - { - if (entity.getEntityKind().equals("PROJECT")) - { - if (incomingProjectPermIds.contains(entity.getPermId()) == false) - { - projectPermIds.add(new ProjectPermId(entity.getPermId())); - } - } - else if (entity.getEntityKind().equals("EXPERIMENT")) - { - if (incomingExperimentPermIds.contains(entity.getPermId()) == false) - { - experimentPermIds.add(new ExperimentPermId(entity.getPermId())); - } - else - { - String typeCodeOrNull = entity.getTypeCodeOrNull(); - NewExperiment exp = data.getExperimentsToProcess().get(entity.getPermId()).getExperiment(); - if (typeCodeOrNull.equals(exp.getExperimentTypeCode()) == false) - { - experimentPermIds.add(new ExperimentPermId(entity.getPermId())); - } - } - } - else if (entity.getEntityKind().equals("SAMPLE")) - { - if (incomingSamplePermIds.contains(entity.getPermId()) == false) - { - samplePermIds.add(new SamplePermId(entity.getPermId())); - } - else - { - String typeCodeOrNull = entity.getTypeCodeOrNull(); - NewSample smp = data.getSamplesToProcess().get(entity.getPermId()).getSample(); - if (typeCodeOrNull.equals(smp.getSampleType().getCode()) == false) - { - samplePermIds.add(new SamplePermId(entity.getPermId())); - } - } - } - else if (entity.getEntityKind().equals("DATA_SET")) - { - if (incomingDataSetCodes.contains(entity.getPermId()) == false) - { - dsPermIds.add(new DataSetPermId(entity.getPermId())); - } - else - { - boolean sameDS = true; - // if (ds.getKind() == DataSetKind.PHYSICAL && ds.lastModificationDate.after(lastSyncDate)) - String typeCodeOrNull = entity.getTypeCodeOrNull(); - - DataSetWithConnections dsWithConns = data.getDataSetsToProcess().get(entity.getPermId()); - NewExternalData ds = dsWithConns.getDataSet(); - if (typeCodeOrNull.equals(ds.getDataSetType().getCode()) == false) - { - sameDS = false; - } - else - { - if (dsWithConns.getKind() == DataSetKind.PHYSICAL && dsWithConns.getLastModificationDate().after(lastSyncTimestamp)) - { - PhysicalDataSet physicalDS = service.tryGetDataSet(entity.getPermId()).tryGetAsDataSet(); - sameDS = deepCompareDataSets(entity.getPermId()); - if (sameDS == false) - physicalDataSetsDelete.add(physicalDS); - } - } - if (sameDS == false) - { - dsPermIds.add(new DataSetPermId(entity.getPermId())); - } - } - } - } - } - - List<ch.ethz.sis.openbis.generic.asapi.v3.dto.material.Material> materials = entityRetriever.fetchMaterials(); - - for (ch.ethz.sis.openbis.generic.asapi.v3.dto.material.Material material : materials) - { - if (incomingMaterialCodes.contains(material.getCode()) == false) - { - matPermIds.add(new MaterialPermId(material.getCode(), material.getType().getCode())); - } - } - - IApplicationServerApi v3Api = ServiceProvider.getV3ApplicationService(); - - // delete data sets - DataSetDeletionOptions dsDeletionOpts = new DataSetDeletionOptions(); - dsDeletionOpts.setReason("sync data set deletions"); // TODO maybe mention data source space id in the reason - - IDeletionId dsDeletionId = - v3Api.deleteDataSets(sessionToken, dsPermIds, dsDeletionOpts); - - // delete samples - SampleDeletionOptions sampleDeletionOptions = new SampleDeletionOptions(); - sampleDeletionOptions.setReason("sync sample deletions"); - IDeletionId smpDeletionId = v3Api.deleteSamples(sessionToken, samplePermIds, sampleDeletionOptions); - - // delete experiments - ExperimentDeletionOptions expDeletionOpts = new ExperimentDeletionOptions(); - expDeletionOpts.setReason("sync experiment deletions"); - IDeletionId expDeletionId = v3Api.deleteExperiments(sessionToken, experimentPermIds, expDeletionOpts); - - // delete projects - ProjectDeletionOptions prjDeletionOpts = new ProjectDeletionOptions(); - prjDeletionOpts.setReason("Sync projects"); - v3Api.deleteProjects(sessionToken, projectPermIds, prjDeletionOpts); - - // delete materials - MaterialDeletionOptions matDeletionOptions = new MaterialDeletionOptions(); - matDeletionOptions.setReason("sync materials"); - v3Api.deleteMaterials(sessionToken, matPermIds, matDeletionOptions); - - // confirm deletions - ArrayList<IDeletionId> deletionIds = new ArrayList<IDeletionId>(); - - StringBuffer summary = new StringBuffer(); - if (projectPermIds.size() > 0) - { - summary.append(projectPermIds.size() + " projects,"); - } - if (matPermIds.size() > 0) - { - summary.append(matPermIds.size() + " materials,"); - } - if (expDeletionId != null) - { - deletionIds.add(expDeletionId); - summary.append(experimentPermIds.size() + " experiments,"); - } - if (smpDeletionId != null) - { - deletionIds.add(smpDeletionId); - summary.append(samplePermIds.size() + " samples,"); - } - if (dsDeletionId != null) - { - deletionIds.add(dsDeletionId); - summary.append(dsPermIds.size() + " data sets"); - } - v3Api.confirmDeletions(sessionToken, deletionIds); // Arrays.asList(expDeletionId, dsDeletionId, smpDeletionId) - - if (summary.length() > 0) - { - operationLog.info(summary.substring(0, summary.length() - 1) + " have been deleted:"); - } - for (PhysicalDataSet physicalDS : physicalDataSetsDelete) - { - operationLog.info("Is going to delete the location: " + physicalDS.getLocation()); - File datasetDir = - getDirectoryProvider().getDataSetDirectory(physicalDS); - SegmentedStoreUtils.deleteDataSetInstantly(physicalDS.getCode(), datasetDir, new Log4jSimpleLogger(operationLog)); - } - } - - private void processExperiments(ResourceListParserData data, - AtomicEntityOperationDetailsBuilder builder) - { - // process experiments - Map<String, ExperimentWithConnections> experimentsToProcess = data.getExperimentsToProcess(); - for (ExperimentWithConnections exp : experimentsToProcess.values()) - { - NewExperiment newIncomingExp = exp.getExperiment(); - if (exp.getLastModificationDate().after(lastSyncTimestamp)) - { - Experiment experiment = null; - try - { - experiment = service.tryGetExperimentByPermId(newIncomingExp.getPermID()); - } catch (Exception e) - { - // doing nothing because when the experiment with the perm id not found - // an exception will be thrown. Seems to be the same with entity kinds - } - - if (experiment == null) - { - // ADD EXPERIMENT - builder.experiment(newIncomingExp); - } - else - { - // UPDATE EXPERIMENT - ExperimentUpdatesDTO expUpdate = createExperimentUpdateDTOs(newIncomingExp, experiment); - builder.experimentUpdate(expUpdate); - } - } - handleExperimentConnections(data, exp, newIncomingExp); - } - } - - private void handleExperimentConnections(ResourceListParserData data, ExperimentWithConnections exp, NewExperiment newIncomingExp) - { - Map<String, SampleWithConnections> samplesToProcess = data.getSamplesToProcess(); - Map<String, DataSetWithConnections> dataSetsToProcess = data.getDataSetsToProcess(); - for (Connection conn : exp.getConnections()) - { - if (samplesToProcess.containsKey(conn.getToPermId())) - { - SampleWithConnections sample = samplesToProcess.get(conn.getToPermId()); - NewSample newSample = sample.getSample(); - newSample.setExperimentIdentifier(newIncomingExp.getIdentifier()); - } - if (dataSetsToProcess.containsKey(conn.getToPermId())) - { - NewExternalData externalData = dataSetsToProcess.get(conn.getToPermId()).getDataSet(); - externalData.setExperimentIdentifierOrNull(ExperimentIdentifierFactory.parse(newIncomingExp.getIdentifier())); - } - } - } - - private ExperimentUpdatesDTO createExperimentUpdateDTOs(NewExperiment newIncomingExp, Experiment experiment) - { - ExperimentUpdatesDTO expUpdate = new ExperimentUpdatesDTO(); - expUpdate.setProjectIdentifier(ExperimentIdentifierFactory.parse(newIncomingExp.getIdentifier())); - expUpdate.setVersion(experiment.getVersion()); - expUpdate.setProperties(Arrays.asList(newIncomingExp.getProperties())); - expUpdate.setExperimentId(TechId.create(experiment)); - // TODO attachments - expUpdate.setAttachments(Collections.<NewAttachment> emptyList()); - return expUpdate; - } - - private void processMaterials(ResourceListParserData data, AtomicEntityOperationDetailsBuilder builder) - { - // process materials - Map<String, MaterialWithLastModificationDate> materialsToProcess = data.getMaterialsToProcess(); - for (MaterialWithLastModificationDate newMaterialWithType : materialsToProcess.values()) - { - NewMaterialWithType newIncomingMaterial = newMaterialWithType.getMaterial(); - if (newMaterialWithType.getLastModificationDate().after(lastSyncTimestamp)) - { - Material material = service.tryGetMaterial(new MaterialIdentifier(newIncomingMaterial.getCode(), newIncomingMaterial.getType())); - if (material == null) - { - builder.material(newIncomingMaterial); - } - else - { - MaterialUpdateDTO update = - new MaterialUpdateDTO(TechId.create(material), Arrays.asList(newIncomingMaterial.getProperties()), - material.getModificationDate()); - builder.materialUpdate(update); - } - } - } - } - - private void processProjects(ResourceListParserData data, AtomicEntityOperationDetailsBuilder builder) - { - Map<String, ProjectWithConnections> projectsToProcess = data.getProjectsToProcess(); - for (ProjectWithConnections prj : projectsToProcess.values()) - { - NewProject incomingProject = prj.getProject(); - if (prj.getLastModificationDate().after(lastSyncTimestamp)) - { - Project project = null; - try - { - project = service.tryGetProjectByPermId(incomingProject.getPermID()); - } catch (Exception e) - { - // TODO doing nothing because when the project with the perm is not found - // an exception will be thrown. See bug report SSDM-4108 - } - - if (project == null) - { - // ADD PROJECT - builder.project(incomingProject); - } - else - { - // UPDATE PROJECT - builder.projectUpdate(createProjectUpdateDTO(incomingProject, project)); - } - } - // handleProjectConnections(data, prj); - } - } - - private void handleProjectConnections(ResourceListParserData data, ProjectWithConnections prj) - { - Map<String, ExperimentWithConnections> experimentsToProcess = data.getExperimentsToProcess(); - for (Connection conn : prj.getConnections()) - { - String connectedExpPermId = conn.getToPermId(); - // TODO we need to do the same check for samples to support project samples - if (experimentsToProcess.containsKey(connectedExpPermId)) - { - // the project is connected to an experiment - ExperimentWithConnections exp = experimentsToProcess.get(connectedExpPermId); - NewExperiment newExp = exp.getExperiment(); - Experiment experiment = service.tryGetExperimentByPermId(connectedExpPermId); - // check if our local graph has the same connection - if (service.tryGetExperiment(ExperimentIdentifierFactory.parse(newExp.getIdentifier())) == null) - { - // add new edge - String oldIdentifier = newExp.getIdentifier(); - int index = oldIdentifier.lastIndexOf('/'); - String expCode = oldIdentifier.substring(index + 1); - newExp.setIdentifier(prj.getProject().getIdentifier() + "/" + expCode); - // add new experiment node - } - } - else - { - // This means the XML contains the connection but not the connected entity. - // This is an unlikely scenario. - operationLog.info("Connected experiment with permid : " + connectedExpPermId + " is missing"); - } - } - } - - private ProjectUpdatesDTO createProjectUpdateDTO(NewProject incomingProject, Project project) - { - ProjectUpdatesDTO prjUpdate = new ProjectUpdatesDTO(); - prjUpdate.setVersion(project.getVersion()); - prjUpdate.setTechId(TechId.create(project)); - prjUpdate.setDescription(incomingProject.getDescription()); - // TODO attachments???? - prjUpdate.setAttachments(Collections.<NewAttachment> emptyList()); - ProjectIdentifier projectIdentifier = ProjectIdentifierFactory.parse(incomingProject.getIdentifier()); - prjUpdate.setSpaceCode(projectIdentifier.getSpaceCode()); - return prjUpdate; - } - - private void processSamples(ResourceListParserData data, AtomicEntityOperationDetailsBuilder builder) - { - // process samples - Map<String, SampleWithConnections> samplesToProcess = data.getSamplesToProcess(); - Map<SampleIdentifier, NewSample> samplesToUpdate = new HashMap<SampleIdentifier, NewSample>(); - Set<String> sampleWithUpdatedParents = new HashSet<String>(); - for (SampleWithConnections sample : samplesToProcess.values()) - { - NewSample incomingSample = sample.getSample(); - if (sample.getLastModificationDate().after(lastSyncTimestamp)) - { - SampleIdentifier sampleIdentifier = SampleIdentifierFactory.parse(incomingSample); - Sample sampleWithExperiment = null; - try - { - sampleWithExperiment = service.tryGetSampleByPermId(incomingSample.getPermID()); - } catch (Exception e) - { - // doing nothing because when the sample with the perm is not found - // an exception will be thrown. See the same issue for projects - } - if (sampleWithExperiment == null) - { - // ADD SAMPLE - builder.sample(incomingSample); - } - else - { - // defer creation of sample update objects until all samples have been gone through; - samplesToUpdate.put(sampleIdentifier, incomingSample); - List<Sample> childSamples = getChildSamples(sampleWithExperiment); - for (Sample child : childSamples) - { - String childSampleIdentifier = child.getIdentifier();// edgeNodePair.getNode().getIdentifier(); - SampleWithConnections childSampleWithConns = findChildInSamplesToProcess(childSampleIdentifier, samplesToProcess); - if (childSampleWithConns == null) - { - // TODO Handle sample delete - } - else - { - // the childSample will appear in the incoming samples list anyway - // but we want to make sure its parent modification is handled - NewSample childSample = childSampleWithConns.getSample(); - sampleWithUpdatedParents.add(childSample.getIdentifier()); - } - } - } - } - for (Connection conn : sample.getConnections()) - { - if (conn.getType().equals("Component")) - { - NewSample containedSample = samplesToProcess.get(conn.getToPermId()).getSample(); - containedSample.setContainerIdentifier(incomingSample.getIdentifier()); - } - else if (conn.getType().equals("Child")) - { - NewSample childSample = samplesToProcess.get(conn.getToPermId()).getSample(); - String[] parents = childSample.getParentsOrNull(); - List<String> parentIds = null; - if (parents == null) - { - parentIds = new ArrayList<String>(); - } - else - { - parentIds = new ArrayList<String>(Arrays.asList(parents)); - } - parentIds.add(incomingSample.getIdentifier()); - childSample.setParentsOrNull(parentIds.toArray(new String[parentIds.size()])); - } - // TODO how about Connection Type - // else if (conn.getType().equals("Connection")) // TODO not sure if this guarantees that we have a dataset in the toPermId - // { - // NewExternalData externalData = dataSetsToCreate.get(conn.getToPermId()).getDataSet(); - // externalData.setSampleIdentifierOrNull(new SampleIdentifier(newSmp.getIdentifier())); - // } - } - } - - // create sample update dtos for the samples that need to be updated - for (SampleIdentifier sampleIdentifier : samplesToUpdate.keySet()) - { - NewSample newSmp = samplesToUpdate.get(sampleIdentifier); - Sample sampleWithExperiment = service.tryGetSampleByPermId(newSmp.getPermID()); - - TechId sampleId = TechId.create(sampleWithExperiment); - ExperimentIdentifier experimentIdentifier = getExperimentIdentifier(newSmp); - ProjectIdentifier projectIdentifier = getProjectIdentifier(newSmp); - String[] modifiedParentIds = newSmp.getParentsOrNull(); - if (modifiedParentIds == null) - { - if (sampleWithUpdatedParents.contains(newSmp.getIdentifier())) - { - modifiedParentIds = new String[0]; - } - } - String containerIdentifier = getContainerIdentifier(newSmp); - - SampleUpdatesDTO updates = - new SampleUpdatesDTO(sampleId, Arrays.asList(newSmp.getProperties()), experimentIdentifier, - projectIdentifier, Collections.<NewAttachment> emptyList(), - sampleWithExperiment.getVersion(), sampleIdentifier, containerIdentifier, - modifiedParentIds); - builder.sampleUpdate(updates); - } - } - - private String getContainerIdentifier(NewSample newSmp) - { - String containerIdentifier = newSmp.getContainerIdentifier(); - return containerIdentifier == null ? null : containerIdentifier; - } - - private ExperimentIdentifier getExperimentIdentifier(NewSample newSmp) - { - String expIdentifier = newSmp.getExperimentIdentifier(); - if (expIdentifier == null) - { - return null; - } - return ExperimentIdentifierFactory.parse(expIdentifier); - } - - private ProjectIdentifier getProjectIdentifier(NewSample sample) - { - String projectIdentifier = sample.getProjectIdentifier(); - if (projectIdentifier == null) - { - return null; - } - return ProjectIdentifierFactory.parse(projectIdentifier); - } - private List<Sample> getChildSamples(Sample sampleWithExperiment) - { - ListSampleCriteria criteria = ListSampleCriteria.createForParent(new TechId(sampleWithExperiment.getId())); - return service.listSamples(criteria); - } - - private SampleWithConnections findChildInSamplesToProcess(String childSampleIdentifier, Map<String, SampleWithConnections> samplesToProcess) - { - for (SampleWithConnections sample : samplesToProcess.values()) - { - if (sample.getSample().getIdentifier().equals(childSampleIdentifier)) - { - return sample; - } - } - return null; - } - - private final class DataSetRegistrationTaskExecutor implements ITaskExecutor<DataSetWithConnections> - { - - private List<String> notRegisteredDataSetCodes; - - public DataSetRegistrationTaskExecutor(List<String> notRegisteredDataSetCodes) - { - this.notRegisteredDataSetCodes = notRegisteredDataSetCodes; - } - - @Override - public Status execute(DataSetWithConnections dataSet) - { - System.out.println("start " + dataSet.getDataSet().getCode()); - - Properties props = setProperties(); - - DataSetRegistrationIngestionService ingestionService = - new DataSetRegistrationIngestionService(props, storeRoot, notRegisteredDataSetCodes, dataSet.getDataSet(), operationLog); - TableModel resultTable = ingestionService.createAggregationReport(new HashMap<String, Object>(), context); - if (resultTable != null) - { - List<TableModelColumnHeader> headers = resultTable.getHeader(); - String[] stringArray = new String[headers.size()]; - for (int i = 0; i < stringArray.length; i++) - { - if (headers.get(i).getTitle().startsWith("Error")) - { - String message = resultTable.getRows().get(0).getValues().toString(); - notRegisteredDataSetCodes.add(dataSet.getDataSet().getCode()); - operationLog.error(message); - return Status.createError(message); - } - } - } - return Status.OK; - } - - private Properties setProperties() - { - Properties props = new Properties(); - props.setProperty("user", EntitySynchronizer.this.config.getUser()); - props.setProperty("pass", EntitySynchronizer.this.config.getPassword()); - props.setProperty("as-url", EntitySynchronizer.this.config.getDataSourceOpenbisURL()); - props.setProperty("dss-url", EntitySynchronizer.this.config.getDataSourceDSSURL()); - props.setProperty("harvester-temp-dir", EntitySynchronizer.this.config.getHarvesterTempDir()); - props.setProperty("do-not-create-original-dir", "true"); - return props; - } - } - - private boolean deepCompareDataSets(String dataSetCode) - throws NoSuchAlgorithmException, UnsupportedEncodingException - { - // get the file nodes in the incoming DS by querying the data source openbis - String asUrl = config.getDataSourceOpenbisURL(); - String dssUrl = config.getDataSourceDSSURL(); - - DSSFileUtils dssFileUtils = DSSFileUtils.create(asUrl, dssUrl); - String sessionToken = dssFileUtils.login(config.getUser(), config.getPassword()); - - DataSetFileSearchCriteria criteria = new DataSetFileSearchCriteria(); - criteria.withDataSet().withCode().thatEquals(dataSetCode); - SearchResult<DataSetFile> result = dssFileUtils.searchFiles(sessionToken, criteria, new DataSetFileFetchOptions()); - - // get the file nodes in the harvester openbis - IDataStoreServerApi dssharvester = (IDataStoreServerApi) ServiceProvider.getDssServiceV3().getService(); - SearchResult<DataSetFile> resultHarvester = - dssharvester.searchFiles(ServiceProvider.getOpenBISService().getSessionToken(), criteria, new DataSetFileFetchOptions()); - if (result.getTotalCount() != resultHarvester.getTotalCount()) - { - return false; - } - List<DataSetFile> dsNodes = result.getObjects(); - List<DataSetFile> harvesterNodes = resultHarvester.getObjects(); - sortFileNodes(dsNodes); - sortFileNodes(harvesterNodes); - return calculateHash(dsNodes).equals(calculateHash(harvesterNodes)); - } - - private void sortFileNodes(List<DataSetFile> nodes) - { - Collections.sort(nodes, new Comparator<DataSetFile>() - { - - @Override - public int compare(DataSetFile dsFile1, DataSetFile dsFile2) - { - return dsFile1.getPath().compareTo(dsFile2.getPath()); - } - }); - } - - private String calculateHash(List<DataSetFile> nodes) throws NoSuchAlgorithmException, UnsupportedEncodingException - { - StringBuffer sb = new StringBuffer(); - for (DataSetFile dataSetFile : nodes) - { - sb.append(dataSetFile.getPath()); - sb.append(dataSetFile.getChecksumCRC32()); - sb.append(dataSetFile.getFileLength()); - } - byte[] digest = MessageDigest.getInstance("MD5").digest(new String(sb).getBytes("UTF-8")); - return new String(Hex.encodeHex(digest)); - } - - private DataSetBatchUpdatesDTO createDataSetBatchUpdateDTO(NewExternalData childDS, AbstractExternalData dsInHarvester) - { - ch.systemsx.cisd.etlserver.registrator.api.v1.impl.DataSetUpdatable updateUpdatable = new - ch.systemsx.cisd.etlserver.registrator.api.v1.impl.DataSetUpdatable(dsInHarvester, service); - DataSetBatchUpdatesDTO dsBatchUpdatesDTO = ConversionUtils.convertToDataSetBatchUpdatesDTO(updateUpdatable); - dsBatchUpdatesDTO.setDatasetId(TechId.create(dsInHarvester)); - List<IEntityProperty> entityProperties = new ArrayList<IEntityProperty>(); - for (NewProperty prop : childDS.getDataSetProperties()) - { - String propertyCode = prop.getPropertyCode(); - String value = prop.getValue(); - entityProperties.add(new PropertyBuilder(propertyCode).value(value).getProperty()); - } - dsBatchUpdatesDTO.setProperties(entityProperties); - return dsBatchUpdatesDTO; - } - - private IDataSetDirectoryProvider getDirectoryProvider() - { - return new DataSetDirectoryProvider(getConfigProvider().getStoreRoot(), getShareIdManager()); - } - - private IConfigProvider getConfigProvider() - { - return ServiceProvider.getConfigProvider(); - } - - private IShareIdManager getShareIdManager() - { - return ServiceProvider.getShareIdManager(); - } - -} diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/MasterDataParser.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/MasterDataParser.java deleted file mode 100644 index 12cc343809016a1a32fa4513b94159216b8b6692..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/MasterDataParser.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2016 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.harvester.synchronizer; - -import java.util.HashMap; -import java.util.Map; - -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpression; -import javax.xml.xpath.XPathExpressionException; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.DataType; -import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.IMasterDataRegistrationTransaction; -import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.IPropertyAssignment; -import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.IPropertyType; -import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.ISampleType; -import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.IVocabulary; -import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.IVocabularyTerm; - -/** - * - * - * @author Ganime Betul Akin - */ -public class MasterDataParser -{ - private final IMasterDataRegistrationTransaction masterDataRegistrationTransaction; - - private Map<String, IPropertyType> propertyTypeMap = new HashMap<String, IPropertyType>(); - - private Map<String, IVocabulary> vocabularyMap = new HashMap<String, IVocabulary>(); - - /** - * @param masterDataRegistrationTransaction - */ - public MasterDataParser(IMasterDataRegistrationTransaction masterDataRegistrationTransaction) - { - this.masterDataRegistrationTransaction = masterDataRegistrationTransaction; - } - - public void parseMasterData(Document doc, XPath xpath, String uri) throws XPathExpressionException - { - XPathExpression expr = - xpath.compile("//s:url/s:loc[normalize-space(.)='" + uri + "']//following-sibling::*[local-name() = 'masterData'][1]"); - Node xdNode = (Node) expr.evaluate(doc, XPathConstants.NODE); - if (xdNode == null) - { - throw new XPathExpressionException("The master data resurce list should contain 1 master data element"); - } - Element docElement = (Element) xdNode; - - parseVocabularies(docElement.getElementsByTagName("vocabularies")); - parsePropertyTypes(docElement.getElementsByTagName("propertyTypes")); - parseSampleTypes(docElement.getElementsByTagName("sampleTypes")); - } - - private void parseVocabularies(NodeList vocabulariesNode) - { - if (vocabulariesNode.getLength() == 1) - { - Element vocabsElement = (Element) vocabulariesNode.item(0); - NodeList vocabNodes = vocabsElement.getElementsByTagName("vocabulary"); - for (int i = 0; i < vocabNodes.getLength(); i++) - { - Element vocabElement = (Element) vocabNodes.item(i); - String code = getAttribute(vocabElement, "code"); - if (code.startsWith("$")) - continue; - //TODO complete other attributes - IVocabulary newVocabulary = masterDataRegistrationTransaction.getOrCreateNewVocabulary(code); - newVocabulary.setDescription(getAttribute(vocabElement, "description")); - newVocabulary.setUrlTemplate(getAttribute(vocabElement, "urlTemplate")); - newVocabulary.setInternalNamespace(Boolean.valueOf(getAttribute(vocabElement, "internalNamespace"))); - newVocabulary.setManagedInternally(Boolean.valueOf(getAttribute(vocabElement, "managedInternally"))); - newVocabulary.setChosenFromList(Boolean.valueOf(getAttribute(vocabElement, "chosenFromList"))); - vocabularyMap.put(code, newVocabulary); - parseVocabularyTerms(vocabElement, newVocabulary); - } - } - } - - private void parseVocabularyTerms(Element vocabElement, IVocabulary newVocabulary) - { - NodeList termNodes = vocabElement.getElementsByTagName("term"); - for (int i = 0; i < termNodes.getLength(); i++) - { - Element termElement = (Element) termNodes.item(i); - String code = getAttribute(termElement, "code"); - IVocabularyTerm newVocabularyTerm = masterDataRegistrationTransaction.createNewVocabularyTerm(code); - newVocabularyTerm.setLabel(getAttribute(termElement, "label")); - newVocabularyTerm.setDescription(getAttribute(termElement, "description")); - newVocabularyTerm.setOrdinal(Long.valueOf(getAttribute(termElement, "ordinal"))); - // TODO setUrl? - newVocabulary.addTerm(newVocabularyTerm); - } - } - - private String getAttribute(Element termElement, String attr) - { - return termElement.getAttributes().getNamedItem(attr).getTextContent(); - } - - private void parseSampleTypes(NodeList sampleTypesNode) - { - if (sampleTypesNode.getLength() == 1) - { - Element sampleTypesElement = (Element) sampleTypesNode.item(0); - NodeList sampleTypeNodes = sampleTypesElement.getElementsByTagName("sampleType"); - for (int i = 0; i < sampleTypeNodes.getLength(); i++) - { - Element sampleTypeElement = (Element) sampleTypeNodes.item(i); - String code = getAttribute(sampleTypeElement, "code"); - ISampleType newSampleType = masterDataRegistrationTransaction.getOrCreateNewSampleType(code); - newSampleType.setGeneratedCodePrefix("S"); - - handlePropertyAssignments(newSampleType, sampleTypeElement.getElementsByTagName("propertyAssignments")); - } - } - } - - private void handlePropertyAssignments(ISampleType newSampleType, NodeList propertyAssignmentsNode) - { - if (propertyAssignmentsNode.getLength() == 1) - { - Element propertyAssignmentsElement = (Element) propertyAssignmentsNode.item(0); - NodeList propertyAssignmentNodes = propertyAssignmentsElement.getElementsByTagName("propertyAssigment"); - for (int i = 0; i < propertyAssignmentNodes.getLength(); i++) - { - Element propertyAssignmentElement = (Element) propertyAssignmentNodes.item(i); - // TODO set other attributes - String property_type_code = getAttribute(propertyAssignmentElement, "property_type_code"); - String data_type_code = getAttribute(propertyAssignmentElement, "data_type_code"); - if (property_type_code.startsWith("$")) - continue; - boolean mandatory = Boolean.valueOf(getAttribute(propertyAssignmentElement, "mandatory")); - long ordinal = Long.valueOf(getAttribute(propertyAssignmentElement, "ordinal")); - String section = getAttribute(propertyAssignmentElement, "section"); - - if (propertyTypeMap.get(property_type_code) != null) - { - IPropertyAssignment assignment = - masterDataRegistrationTransaction.assignPropertyType(newSampleType, propertyTypeMap.get(property_type_code)); - assignment.setMandatory(mandatory); - assignment.setSection(section); - } - } - } - } - - private void parsePropertyTypes(NodeList propertyTypesNode) - { - if (propertyTypesNode.getLength() == 1) - { - Element propertyTypesElement = (Element) propertyTypesNode.item(0); - NodeList propertyTypeNodes = propertyTypesElement.getElementsByTagName("propertyType"); - for (int i = 0; i < propertyTypeNodes.getLength(); i++) - { - Element propertyTypeElement = (Element) propertyTypeNodes.item(i); - String code = getAttribute(propertyTypeElement, "code"); - // TODO handle internal properties - if (code.startsWith("$")) - continue; - String label = getAttribute(propertyTypeElement, "label"); - String dataType = getAttribute(propertyTypeElement, "dataType"); - String description = getAttribute(propertyTypeElement, "description"); - boolean internalNamespace = Boolean.valueOf(getAttribute(propertyTypeElement, "internalNamespace")); - boolean managedInternally = Boolean.valueOf(getAttribute(propertyTypeElement, "managedInternally")); - String vocabulary = null; - Node namedItem = propertyTypeElement.getAttributes().getNamedItem("vocabulary"); - if (namedItem != null) - { - vocabulary = namedItem.getTextContent(); - } - - IPropertyType newPropertyType = masterDataRegistrationTransaction.getOrCreateNewPropertyType(code, DataType.valueOf(dataType)); - propertyTypeMap.put(code, newPropertyType); - newPropertyType.setInternalNamespace(internalNamespace); - newPropertyType.setManagedInternally(managedInternally); - newPropertyType.setLabel(label); - newPropertyType.setDescription(description); - if (vocabulary != null) - { - newPropertyType.setVocabulary(vocabularyMap.get(vocabulary)); - } - // TODO handle the case for property types that are of data type material - } - } - } -} diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/ResourceListParser.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/ResourceListParser.java deleted file mode 100644 index 728403185c5091505d53cc24e490efdb8a0e9ff2..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/ResourceListParser.java +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Copyright 2016 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.harvester.synchronizer; - -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.xml.XMLConstants; -import javax.xml.namespace.NamespaceContext; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpression; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSetKind; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.ResourceListParserData.Connection; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.ResourceListParserData.DataSetWithConnections; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.ResourceListParserData.ExperimentWithConnections; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.ResourceListParserData.MaterialWithLastModificationDate; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.ResourceListParserData.ProjectWithConnections; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.ResourceListParserData.SampleWithConnections; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.translator.DefaultNameTranslator; -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.synchronizer.translator.INameTranslator; -import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.IMasterDataRegistrationTransaction; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityProperty; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewAttachment; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewExperiment; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewMaterialWithType; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewProject; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType; -import ch.systemsx.cisd.openbis.generic.shared.dto.NewContainerDataSet; -import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData; -import ch.systemsx.cisd.openbis.generic.shared.dto.NewProperty; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ProjectIdentifier; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier; - -/** - * @author Ganime Betul Akin - */ -public class ResourceListParser -{ - private final ResourceListParserData data; - - private final INameTranslator nameTranslator; - - private final String dataStoreCode; - - private final IMasterDataRegistrationTransaction masterDataRegistrationTransaction; - - public INameTranslator getNameTranslator() - { - return nameTranslator; - } - - private ResourceListParser(INameTranslator nameTranslator, String dataStoreCode, - IMasterDataRegistrationTransaction masterDataRegistrationTransaction) - { - this.data = new ResourceListParserData(); - this.nameTranslator = nameTranslator; - this.dataStoreCode = dataStoreCode; - this.masterDataRegistrationTransaction = masterDataRegistrationTransaction; - } - - public static ResourceListParser create(INameTranslator nameTranslator, String dataStoreCode, - IMasterDataRegistrationTransaction masterDataRegistrationTransaction) - { - if (nameTranslator == null) - { - return create(dataStoreCode, masterDataRegistrationTransaction); - } - return new ResourceListParser(nameTranslator, dataStoreCode, masterDataRegistrationTransaction); - } - - public static ResourceListParser create(String dataStoreCode, IMasterDataRegistrationTransaction masterDataRegistrationTransaction) - { - return create(new DefaultNameTranslator(), dataStoreCode, masterDataRegistrationTransaction); - } - - public ResourceListParserData parseResourceListDocument(Document doc) throws XPathExpressionException - { - XPath xpath = XPathFactory.newInstance().newXPath(); - xpath.setNamespaceContext(new NamespaceContext() - { - public String getNamespaceURI(String prefix) - { - if (prefix == null) - throw new NullPointerException("Null prefix"); - else if ("s".equals(prefix)) - return "http://www.sitemaps.org/schemas/sitemap/0.9"; - else if ("rs".equals(prefix)) - return "http://www.openarchives.org/rs/terms/"; - else if ("x".equals(prefix)) - return "https://sis.id.ethz.ch/software/#openbis/xdterms/"; - else if ("xml".equals(prefix)) - return XMLConstants.XML_NS_URI; - return XMLConstants.NULL_NS_URI; - } - - // This method isn't necessary for XPath processing. - public String getPrefix(String uri) - { - throw new UnsupportedOperationException("Not implemented!!!"); - } - - // This method isn't necessary for XPath processing either. - public Iterator<?> getPrefixes(String uri) - { - 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; - } - - private Date getResourceListTimestamp(Document doc, XPath xpath) throws XPathExpressionException - { - XPathExpression expr = xpath.compile("*[name() = 'urlset']/*[name() = 'rs:md']"); - Node mdNode = (Node) expr.evaluate(doc, XPathConstants.NODE); - String timestamp = mdNode.getAttributes().getNamedItem("at").getTextContent(); - try - { - return convertFromW3CDate(timestamp); - } catch (ParseException e) - { - throw new XPathExpressionException("Last modification date cannot be parsed:" + timestamp); - } - } - - 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 = new MasterDataParser(masterDataRegistrationTransaction); - mdParser.parseMasterData(doc, xpath, uri); - } - - private void parseUriMetaData(Document doc, XPath xpath, String uri) throws XPathExpressionException - { - Date lastModificationDate = extractLastModificationDate(doc, xpath, uri); - - Node xdNode = extractXdNode(doc, xpath, uri); - String entityKind = xdNode.getAttributes().getNamedItem("kind").getTextContent(); - - if ("PROJECT".equals(entityKind)) - { - parseProjectMetaData(xpath, extractPermIdFromURI(uri), xdNode, lastModificationDate); - } - else if ("EXPERIMENT".equals(entityKind)) - { - parseExperimentMetaData(xpath, extractPermIdFromURI(uri), xdNode, lastModificationDate); - } - else if ("SAMPLE".equals(entityKind)) - { - parseSampleMetaData(xpath, extractPermIdFromURI(uri), xdNode, lastModificationDate); - } - else if ("DATA_SET".equals(entityKind)) - { - parseDataSetMetaData(xpath, extractDataSetCodeFromURI(uri), xdNode, lastModificationDate); - } - else if ("MATERIAL".equals(entityKind)) - { - parseMaterialMetaData(xpath, extractMaterialCodeFromURI(uri), xdNode, lastModificationDate); - } - } - - private Date extractLastModificationDate(Document doc, XPath xpath, String uri) throws XPathExpressionException - { - 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) - { - 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); - } - } - - private Date convertFromW3CDate(String lastModDataStr) throws ParseException - { - DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US); - df1.setTimeZone(TimeZone.getTimeZone("GMT")); - 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) - { - String code = extractCode(xdNode); - String sample = extractAttribute(xdNode, "sample"); - String experiment = extractAttribute(xdNode, "experiment"); - String type = extractType(xdNode); - String dsKind = extractAttribute(xdNode, "dsKind"); - NewExternalData ds = new NewExternalData(); - if (dsKind.equals(DataSetKind.CONTAINER.toString())) - { - ds = new NewContainerDataSet(); - ds.setCode(code); - ds.setDataSetType(new DataSetType(type)); - ds.setDataStoreCode(this.dataStoreCode); - if (sample.trim().equals("") == false) - { - ds.setSampleIdentifierOrNull(getSampleIdentifier(sample)); - } - if (experiment.trim().equals("") == false) - { - ds.setExperimentIdentifierOrNull(getExperimentIdentifier(experiment)); - } - } - else if (dsKind.equals(DataSetKind.PHYSICAL.toString())) - { - ds.setCode(code); - ds.setDataSetType(new DataSetType(type)); - ds.setDataStoreCode(this.dataStoreCode); - if (sample.trim().equals("") == false) - { - ds.setSampleIdentifierOrNull(getSampleIdentifier(sample)); - } - if (experiment.trim().equals("") == false) - { - ds.setExperimentIdentifierOrNull(getExperimentIdentifier(experiment)); - } - } - DataSetWithConnections newDsWithConns = data.new DataSetWithConnections(ds, lastModificationDate); - data.getDataSetsToProcess().put(permId, newDsWithConns); - newDsWithConns.setConnections(parseConnections(xpath, xdNode)); - ds.setDataSetProperties(parseDataSetProperties(xpath, xdNode)); - } - - private String extractAttribute(Node xdNode, String attrName) - { - return xdNode.getAttributes().getNamedItem(attrName).getTextContent(); - } - - private String extractCode(Node xdNode) - { - return extractAttribute(xdNode, "code"); - } - - private SampleIdentifier getSampleIdentifier(String sampleIdentifierStr) - { - SampleIdentifier sampleIdentifier = SampleIdentifierFactory.parse(sampleIdentifierStr); - SpaceIdentifier spaceLevel = sampleIdentifier.getSpaceLevel(); - String originalSpaceCode = spaceLevel.getSpaceCode(); - return new SampleIdentifier(new SpaceIdentifier(nameTranslator.translate(originalSpaceCode)), sampleIdentifier.getSampleCode()); - } - - private ExperimentIdentifier getExperimentIdentifier(String experiment) - { - ExperimentIdentifier experimentIdentifier = ExperimentIdentifierFactory.parse(experiment); - String originalSpaceCode = experimentIdentifier.getSpaceCode(); - String projectCode = experimentIdentifier.getProjectCode(); - String expCode = experimentIdentifier.getExperimentCode(); - return new ExperimentIdentifier(new ProjectIdentifier(nameTranslator.translate(originalSpaceCode), projectCode), expCode); - } - - private void parseProjectMetaData(XPath xpath, String permId, Node xdNode, Date lastModificationDate) - { - - String code = extractCode(xdNode); - String desc = xdNode.getAttributes().getNamedItem("desc").getTextContent(); - String space = extractSpace(xdNode); - // TODO is there a better way to create project identifier below? - NewProject newProject = new NewProject("/" + nameTranslator.translate(space) + "/" + code, desc); - newProject.setPermID(permId); - ProjectWithConnections newPrjWithConns = - data.new ProjectWithConnections(newProject, lastModificationDate); - data.getProjectsToProcess().put(permId, newPrjWithConns); - newPrjWithConns.setConnections(parseConnections(xpath, xdNode)); - } - - private void parseMaterialMetaData(XPath xpath, String permId, Node xdNode, Date lastModificationDate) - { - String code = extractCode(xdNode); - String type = extractType(xdNode); - NewMaterialWithType newMaterial = new NewMaterialWithType(code, type); - MaterialWithLastModificationDate materialWithLastModDate = - data.new MaterialWithLastModificationDate(newMaterial, lastModificationDate); - data.getMaterialsToProcess().put(code, materialWithLastModDate); - newMaterial.setProperties(parseProperties(xpath, xdNode)); - } - - private List<Connection> parseConnections(XPath xpath, Node xdNode) - { - List<Connection> conns = new ArrayList<Connection>(); - Element docElement = (Element) xdNode; - NodeList connsNode = docElement.getElementsByTagName("x:connections"); - if (connsNode.getLength() == 1) - { - Element connsElement = (Element) connsNode.item(0); - NodeList connNodes = connsElement.getElementsByTagName("x:connection"); - for (int i = 0; i < connNodes.getLength(); i++) - { - String to = connNodes.item(i).getAttributes().getNamedItem("to").getTextContent(); - String type = connNodes.item(i).getAttributes().getNamedItem("type").getTextContent(); - conns.add(data.new Connection(to, type)); - } - } - return conns; - } - - private List<NewProperty> parseDataSetProperties(XPath xpath, Node xdNode) - { - - List<NewProperty> dsProperties = new ArrayList<NewProperty>(); - Element docElement = (Element) xdNode; - NodeList propsNode = docElement.getElementsByTagName("x:properties"); - if (propsNode.getLength() == 1) - { - Element propsElement = (Element) propsNode.item(0); - NodeList propertyNodes = propsElement.getElementsByTagName("x:property"); - for (int i = 0; i < propertyNodes.getLength(); i++) - { - Element propertyElement = (Element) propertyNodes.item(i); - // TODO proper error handling needed below in case the XML is not correct and item 0 does not exist - String code = propertyElement.getElementsByTagName("x:code").item(0).getTextContent(); - String val = propertyElement.getElementsByTagName("x:value").item(0).getTextContent(); - dsProperties.add(new NewProperty(code, val)); - } - } - return dsProperties; - } - - private EntityProperty[] parseProperties(XPath xpath, Node xdNode) - { - - List<EntityProperty> entityProperties = new ArrayList<EntityProperty>(); - Element docElement = (Element) xdNode; - NodeList propsNode = docElement.getElementsByTagName("x:properties"); - if (propsNode.getLength() == 1) - { - Element propsElement = (Element) propsNode.item(0); - NodeList propertyNodes = propsElement.getElementsByTagName("x:property"); - for (int i = 0; i < propertyNodes.getLength(); i++) - { - Element propertyElement = (Element) propertyNodes.item(i); - // TODO proper error handling needed below in case the XML is not correct and item 0 does not exist - String code = propertyElement.getElementsByTagName("x:code").item(0).getTextContent(); - String val = propertyElement.getElementsByTagName("x:value").item(0).getTextContent(); - EntityProperty property = createEntityProperty(code, val); - entityProperties.add(property); - } - } - return entityProperties.toArray(new EntityProperty[entityProperties.size()]); - } - - private EntityProperty createEntityProperty(String code, String val) - { - EntityProperty property = new EntityProperty(); - PropertyType propertyType = new PropertyType(); - propertyType.setCode(code); - property.setPropertyType(propertyType); - property.setValue(val); - return property; - } - - private void parseExperimentMetaData(XPath xpath, String permId, Node xdNode, Date lastModificationDate) - { - String code = extractCode(xdNode); - String type = extractType(xdNode); - String project = extractAttribute(xdNode, "project"); - String space = extractSpace(xdNode); - NewExperiment newExp = new NewExperiment("/" + nameTranslator.translate(space) + "/" + project + "/" + code, type); - newExp.setPermID(permId); - ExperimentWithConnections newExpWithConns = data.new ExperimentWithConnections(newExp, lastModificationDate); - data.getExperimentsToProcess().put(permId, newExpWithConns); - newExpWithConns.setConnections(parseConnections(xpath, xdNode)); - newExp.setProperties(parseProperties(xpath, xdNode)); - } - - private void parseSampleMetaData(XPath xpath, String permId, Node xdNode, Date lastModificationDate) - { - String code = extractCode(xdNode); - String type = extractType(xdNode); - String experiment = extractAttribute(xdNode, "experiment"); - String space = extractSpace(xdNode); - SampleType sampleType = new SampleType(); - sampleType.setCode(type); - - NewSample newSample = new NewSample("/" + nameTranslator.translate(space) + "/" + code, sampleType, null, null, - experiment.trim().equals("") ? null : experiment, null, null, new IEntityProperty[0], - new ArrayList<NewAttachment>()); - newSample.setPermID(permId); - SampleWithConnections newSampleWithConns = data.new SampleWithConnections(newSample, lastModificationDate); - data.getSamplesToProcess().put(permId, newSampleWithConns); - newSampleWithConns.setConnections(parseConnections(xpath, xdNode)); - newSample.setProperties(parseProperties(xpath, xdNode)); - } - - private String extractType(Node xdNode) - { - return extractAttribute(xdNode, "type"); - } - - private String extractSpace(Node xdNode) - { - String space = extractAttribute(xdNode, "space"); - data.getHarvesterSpaceList().add(nameTranslator.translate(space)); - return space; - } - - private String extractPermIdFromURI(String uri) throws XPathExpressionException - { - Pattern pattern = Pattern.compile("([0-9\\-]{17,})"); - Matcher matcher = pattern.matcher(uri); - if (matcher.find()) - { - return matcher.group(1); - } - throw new XPathExpressionException("Malformed resource url"); - } - - private String extractDataSetCodeFromURI(String uri) throws XPathExpressionException - { - Pattern pattern = Pattern.compile("(?<=DATA_SET\\/)(.*)(?=\\/M)"); - Matcher matcher = pattern.matcher(uri); - if (matcher.find()) - { - return matcher.group(1); - } - throw new XPathExpressionException("Malformed resource url"); - } - - private String extractMaterialCodeFromURI(String uri) throws XPathExpressionException - { - // TODO malformed uri handling - String[] parts = uri.split("/"); - return parts[parts.length - 2]; - } -} -// expr = xpath.compile("//s:loc[normalize-space(.) ='" + uri + "']/../x:xd/x:properties/x:property"); // -// "//*/text()[normalize-space(.)='" + loc_text + "']/parent::/rs:ln");// "/s:urlset/s:url[/s:loc/text() = '" + -// for (int ji = 0; ji < url_node.getLength(); ji++) -// { -// System.out.print(url_node.item(ji).getNodeName() + ":" + url_node.item(ji).getAttributes().getNamedItem("kind")); -// System.out.println(); -// } - diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/ResourceListParserData.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/ResourceListParserData.java deleted file mode 100644 index ee3c5aff5ed4432b3932d65d56b39a0098e38872..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/ResourceListParserData.java +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright 2016 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.harvester.synchronizer; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSetKind; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewExperiment; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewMaterialWithType; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewProject; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample; -import ch.systemsx.cisd.openbis.generic.shared.dto.NewContainerDataSet; -import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData; -import ch.systemsx.cisd.openbis.generic.shared.dto.NewLinkDataSet; - -/** - * @author Ganime Betul Akin - */ -public class ResourceListParserData -{ - // Introduced to store the timestamp of any still-running transaction on the data source at the time of - // retrieving the resource list. - private Date resourceListTimestamp; - - private Set<String> harvesterSpaceList = new HashSet<>(); - - private Map<String, ProjectWithConnections> projectsToProcess = new HashMap<String, ResourceListParserData.ProjectWithConnections>(); - - private Map<String, ExperimentWithConnections> experimentsToProcess = new HashMap<String, ResourceListParserData.ExperimentWithConnections>(); - - private Map<String, SampleWithConnections> samplesToProcess = new HashMap<String, ResourceListParserData.SampleWithConnections>(); - - private Map<String, DataSetWithConnections> dataSetsToProcess = new HashMap<String, ResourceListParserData.DataSetWithConnections>(); - - private Map<String, MaterialWithLastModificationDate> materialsToProcess = new HashMap<String, MaterialWithLastModificationDate>(); - - public Date getResourceListTimestamp() - { - return resourceListTimestamp; - } - - public void setResourceListTimestamp(Date resourceListTimestamp) - { - this.resourceListTimestamp = resourceListTimestamp; - } - - public Set<String> getHarvesterSpaceList() - { - return harvesterSpaceList; - } - - public Map<String, ProjectWithConnections> getProjectsToProcess() - { - return projectsToProcess; - } - - public Map<String, ExperimentWithConnections> getExperimentsToProcess() - { - return experimentsToProcess; - } - - public Map<String, SampleWithConnections> getSamplesToProcess() - { - return samplesToProcess; - } - - public Map<String, DataSetWithConnections> getDataSetsToProcess() - { - return dataSetsToProcess; - } - - public Map<String, MaterialWithLastModificationDate> getMaterialsToProcess() - { - return materialsToProcess; - } - - public Map<String, DataSetWithConnections> filterPhysicalDataSetsByLastModificationDate(Date lastSyncDate, Set<String> dataSetsCodesToRetry) - { - Map<String, DataSetWithConnections> dsMap = new HashMap<String, ResourceListParserData.DataSetWithConnections>(); - for (String permId : dataSetsToProcess.keySet()) - { - DataSetWithConnections ds = dataSetsToProcess.get(permId); - if (ds.getKind() == DataSetKind.PHYSICAL - && (ds.lastModificationDate.after(lastSyncDate) || dataSetsCodesToRetry.contains(ds.getDataSet().getCode()))) - { - dsMap.put(permId, ds); - } - } - return dsMap; - } - - public Map<String, DataSetWithConnections> filterContainerDataSets() - { - // List<NewDataSetWithConnections> dsList = new ArrayList<ResourceListParserData.NewDataSetWithConnections>(); - Map<String, DataSetWithConnections> dsMap = new HashMap<String, ResourceListParserData.DataSetWithConnections>(); - for (String permId : dataSetsToProcess.keySet()) - { - DataSetWithConnections ds = dataSetsToProcess.get(permId); - if (ds.getKind() == DataSetKind.CONTAINER) - { - dsMap.put(permId, ds); - } - } - return dsMap; - } - - class ProjectWithConnections - { - private final NewProject project; - - private final Date lastModificationDate; - - public NewProject getProject() - { - return project; - } - - private List<Connection> connections = new ArrayList<Connection>(); - - public List<Connection> getConnections() - { - return connections; - } - - ProjectWithConnections(NewProject project, Date lastModDate) - { - this.project = project; - this.lastModificationDate = lastModDate; - } - - public Date getLastModificationDate() - { - return lastModificationDate; - } - - void addConnection(Connection conn) - { - this.connections.add(conn); - } - - public void setConnections(List<Connection> conns) - { - // TODO do this better - this.connections = conns; - } - } - - class ExperimentWithConnections - { - private final NewExperiment experiment; - - private final Date lastModificationDate; - - public NewExperiment getExperiment() - { - return experiment; - } - - public List<Connection> getConnections() - { - return connections; - } - - private List<Connection> connections = new ArrayList<Connection>(); - - ExperimentWithConnections(NewExperiment exp, Date lastModDate) - { - this.experiment = exp; - this.lastModificationDate = lastModDate; - } - - public Date getLastModificationDate() - { - return lastModificationDate; - } - - public void setConnections(List<Connection> conns) - { - // TODO do this better - this.connections = conns; - } - } - - class SampleWithConnections - { - private final NewSample sample; - - private final Date lastModificationDate; - - public Date getLastModificationDate() - { - return lastModificationDate; - } - - public NewSample getSample() - { - return sample; - } - - SampleWithConnections(NewSample sample, Date lastModDate) - { - super(); - this.sample = sample; - this.lastModificationDate = lastModDate; - } - - private List<Connection> connections = new ArrayList<Connection>(); - - public List<Connection> getConnections() - { - return connections; - } - - public void setConnections(List<Connection> conns) - { - // TODO do this better - this.connections = conns; - } - } - - class DataSetWithConnections implements Serializable - { - /** - * - */ - private static final long serialVersionUID = 1L; - private final NewExternalData dataSet; - - private final Date lastModificationDate; - - public Date getLastModificationDate() - { - return lastModificationDate; - } - - public DataSetKind getKind() - { - if (dataSet instanceof NewContainerDataSet) - return DataSetKind.CONTAINER; - else if (dataSet instanceof NewLinkDataSet) - return DataSetKind.LINK; - return DataSetKind.PHYSICAL; - } - - public NewExternalData getDataSet() - { - return dataSet; - } - - DataSetWithConnections(NewExternalData dataSet, Date lastModDate) - { - super(); - this.dataSet = dataSet; - this.lastModificationDate = lastModDate; - } - - private List<Connection> connections = new ArrayList<Connection>(); - - public List<Connection> getConnections() - { - return connections; - } - - public void setConnections(List<Connection> conns) - { - // TODO do this better - this.connections = conns; - } - } - - class Connection - { - final String toPermId; - - final String connType; - - public String getType() - { - return connType; - } - - Connection(String toPermId, String connType) - { - super(); - this.toPermId = toPermId; - this.connType = connType; - } - - public String getToPermId() - { - return toPermId; - } - } - - enum ConnectionType - { - SIMPLE_CONNECTION("Connection"), - PARENT_CHILD_RELATIONSHIP("Child"), - CONTAINER_COMPONENT_RELATIONSHIP("Component"); - - private final String type; - - public String getType() - { - return type; - } - - private ConnectionType(String type) - { - this.type = type; - } - } - - class MaterialWithLastModificationDate - { - private final NewMaterialWithType material; - - private final Date lastModificationDate; - - public NewMaterialWithType getMaterial() - { - return material; - } - - MaterialWithLastModificationDate(NewMaterialWithType material, Date lastModDate) - { - this.material = material; - this.lastModificationDate = lastModDate; - } - - public Date getLastModificationDate() - { - return lastModificationDate; - } - } -} \ No newline at end of file diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/datasourceconnector/DataSourceConnector.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/datasourceconnector/DataSourceConnector.java deleted file mode 100644 index 040c862fc2104f9a7116dcfb2acf09322374d3b8..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/datasourceconnector/DataSourceConnector.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2016 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.harvester.synchronizer.datasourceconnector; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.api.AuthenticationStore; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.client.util.BasicAuthentication; -import org.eclipse.jetty.http.HttpStatus; -import org.w3c.dom.Document; -import org.xml.sax.SAXException; - -import ch.ethz.sis.openbis.generic.server.dss.plugins.harvester.config.BasicAuthCredentials; -import ch.systemsx.cisd.common.http.JettyHttpClientFactory; - -/** - * - * - * @author Ganime Betul Akin - */ -public class DataSourceConnector implements IDataSourceConnector -{ - private final String dataSourceUrl; - - private final BasicAuthCredentials authCredentials; - - public DataSourceConnector(String url, BasicAuthCredentials authCredentials) - { - this.dataSourceUrl = url; - this.authCredentials = authCredentials; - } - - public Document getResourceListAsXMLDoc(List<String> spaceBlackList) throws Exception - { - HttpClient client = JettyHttpClientFactory.getHttpClient(); - addAuthenticationCredentials(client); - Request requestEntity = createNewHttpRequest(client, spaceBlackList); - ContentResponse contentResponse = getResponse(requestEntity); - return parseResponse(contentResponse); - } - - private Document parseResponse(ContentResponse contentResponse) throws ParserConfigurationException, SAXException, IOException - { - DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); - domFactory.setNamespaceAware(true); - byte[] content = contentResponse.getContent(); - ByteArrayInputStream bis = new ByteArrayInputStream(content); - DocumentBuilder builder = domFactory.newDocumentBuilder(); - Document doc = builder.parse(bis); - return doc; - } - - private ContentResponse getResponse(Request requestEntity) throws InterruptedException, TimeoutException, ExecutionException, IOException - { - ContentResponse contentResponse; - contentResponse = requestEntity.send(); - int statusCode = contentResponse.getStatus(); - - if (statusCode != HttpStatus.Code.OK.getCode()) - { - throw new IOException("Resource List could not be retrieved: " + contentResponse.getContentAsString()); - } - return contentResponse; - } - - private Request createNewHttpRequest(HttpClient client, List<String> spaceBlackList) - { - StringBuffer sb = new StringBuffer(); - for (String dataSourceSpace : spaceBlackList) - { - sb.append(dataSourceSpace + ","); - } - String req = dataSourceUrl + "?verb=resourcelist.xml"; - if (sb.length() != 0) - { - String str = sb.toString(); - str = str.substring(0, str.length() - 1); - req += "&black_list=" + str; - } - Request requestEntity = client.newRequest(req).method("GET"); - return requestEntity; - } - - private void addAuthenticationCredentials(HttpClient client) throws URISyntaxException - { - AuthenticationStore auth = client.getAuthenticationStore(); - auth.addAuthentication(new BasicAuthentication(new URI(dataSourceUrl), authCredentials.getRealm(), authCredentials.getUser(), authCredentials - .getPassword())); - } -} diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/datasourceconnector/IDataSourceConnector.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/datasourceconnector/IDataSourceConnector.java deleted file mode 100644 index 2c07794a741a16d2ae115b01497d2ac0d4708577..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/datasourceconnector/IDataSourceConnector.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2016 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.harvester.synchronizer.datasourceconnector; - -import java.util.List; - -import org.w3c.dom.Document; - -/** - * - * - * @author Ganime Betul Akin - */ -public interface IDataSourceConnector -{ - public Document getResourceListAsXMLDoc(List<String> spaceBlackList) throws Exception; -} diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/translator/CustomNameTranslator.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/translator/CustomNameTranslator.java deleted file mode 100644 index 3377f6c5ba1d4c856c659e9722fbcb7fa3905c71..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/translator/CustomNameTranslator.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2016 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.harvester.synchronizer.translator; - -import java.util.HashMap; - -import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; - -/** - * - * - * @author Ganime Betul Akin - */ -public class CustomNameTranslator implements INameTranslator -{ - - private final HashMap<String, String> spaceMappings; - - public CustomNameTranslator(HashMap<String, String> spaceMappings) - { - this.spaceMappings = spaceMappings; - } - - @Override - public String translate(String name) - { - if (spaceMappings == null) - { - throw new ConfigurationFailureException("Space mappings cannot be null"); - } - String newName = spaceMappings.get(name); - if (newName == null) - { - throw new ConfigurationFailureException("No corresponding mapping found for '" + name + "'"); - } - return newName; - } - -} diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/translator/DefaultNameTranslator.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/translator/DefaultNameTranslator.java deleted file mode 100644 index 1203ab2a2c2c8eb116887623397b446290334d9a..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/translator/DefaultNameTranslator.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2016 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.harvester.synchronizer.translator; - -/** - * - * - * @author Ganime Betul Akin - */ -public class DefaultNameTranslator implements INameTranslator -{ - - @Override - public String translate(String name) - { - return name; - } -} diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/translator/INameTranslator.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/translator/INameTranslator.java deleted file mode 100644 index ff31068bba627c846060e1919238626c277624fd..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/translator/INameTranslator.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2016 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.harvester.synchronizer.translator; -/** - * - * - * @author Ganime Betul Akin - */ -public interface INameTranslator -{ - String translate(String name); - -} diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/translator/PrefixBasedNameTranslator.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/translator/PrefixBasedNameTranslator.java deleted file mode 100644 index 58fe522a79d3036aea9ec20e1c5f99b7be6af5fd..0000000000000000000000000000000000000000 --- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/harvester/synchronizer/translator/PrefixBasedNameTranslator.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2016 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.harvester.synchronizer.translator; - -/** - * - * - * @author Ganime Betul Akin - */ -public class PrefixBasedNameTranslator implements INameTranslator -{ - private final String prefix; - - public PrefixBasedNameTranslator(String prefix) - { - this.prefix = prefix; - } - - @Override - public String translate(String name) - { - return prefix + "_" + name; - } - -}