if (config.getProtocol() == null || config.getHosts() == null || config.getUid() == null || config.getSecret() == null) throw new ConfigurationException("must specify endpoints, uid and secret key"); if (config.isRetentionEnabled() && config.getWsChecksumType() == null) log.warn("Retention requires wschecksum. If source objects do not have wschecksum enabled, you may get an error during write"); for (String host : config.getHosts()) { try { endpoints.add(new URI(config.getProtocol().toString(), null, host, config.getPort(), null, null, null)); } catch (URISyntaxException e) { throw new ConfigurationException("invalid host: " + host); config.getUid(), config.getSecret(), endpoints.toArray(new URI[endpoints.size()])); atmosConfig.setEncodeUtf8(config.isEncodeUtf8()); if (config.getAccessType() == namespace) { if (config.getPath() == null) config.setPath("/"); if (!config.getPath().startsWith("/")) config.setPath("/" + config.getPath()); if (!config.getPath().equals("/")) { config.setPath(config.getPath().replaceFirst("/$", "")); // remove trailing slash Map<String, Metadata> sysMeta = atmos.getSystemMetadata(new ObjectPath(config.getPath())); Metadata typeMeta = sysMeta.get(TYPE_PROP); if (typeMeta != null && DIRECTORY_TYPE.equals(typeMeta.getValue())) { if (!config.getPath().endsWith("/")) config.setPath(config.getPath() + "/"); rootSummary = new ObjectSummary(config.getPath(), true, 0);
@Override public Iterable<ObjectSummary> allObjects() { if (config.getAccessType() == AtmosConfig.AccessType.objectspace) throw new UnsupportedOperationException("cannot enumerate objectspace"); // rootSummary is established inside configure(...) if (config.isIncludeTopFolder()) return Collections.singletonList(rootSummary); else return children(rootSummary); }
AtmosConfig atmosTarget = (AtmosConfig) target; Assert.assertEquals("source protocol mismatch", sourceProtocol, atmosSource.getProtocol()); Assert.assertArrayEquals("source hosts mismatch", sourceHosts, atmosSource.getHosts()); Assert.assertEquals("source port mismatch", sourcePort, atmosSource.getPort()); Assert.assertEquals("source uid mismatch", sourceUid, atmosSource.getUid()); Assert.assertEquals("source secret mismatch", sourceSecret, atmosSource.getSecret()); Assert.assertEquals("source path mismatch", sourcePath, atmosSource.getPath()); Assert.assertEquals("source accessType mismatch", sourceAccessType, atmosSource.getAccessType()); Assert.assertTrue("source removeTagsOnDelete should be enabled", atmosSource.isRemoveTagsOnDelete()); Assert.assertEquals("target protocol mismatch", targetProtocol, atmosTarget.getProtocol()); Assert.assertArrayEquals("target hosts mismatch", targetHosts, atmosTarget.getHosts()); Assert.assertEquals("target port mismatch", -1, atmosTarget.getPort()); Assert.assertEquals("target uid mismatch", targetUid, atmosTarget.getUid()); Assert.assertEquals("target secret mismatch", targetSecret, atmosTarget.getSecret()); Assert.assertEquals("target path mismatch", targetPath, atmosTarget.getPath()); Assert.assertEquals("target accessType mismatch", targetAccessType, atmosTarget.getAccessType()); Assert.assertEquals("target wsChecksumType mismatch", targetChecksum, atmosTarget.getWsChecksumType()); Assert.assertTrue("target replaceMetadata should be enabled", atmosTarget.isReplaceMetadata()); Assert.assertTrue("target preserveObjectId should be enabled", atmosTarget.isPreserveObjectId()); Assert.assertEquals(sourceUri, atmosSource.getUri()); Assert.assertEquals(targetUri, atmosTarget.getUri());
if (config.getAccessType() == objectspace) { log.debug("{} is a directory, but target is in objectspace, ignoring", identifier); return null; try { ObjectIdentifier targetId = null; if (config.getAccessType() == namespace) targetId = new ObjectPath(identifier); if (config.getWsChecksumType() != null) { targetOid = createChecksummedObject(targetId, object, config.getWsChecksumType()); } else if (sourceAtmosMeta != null && sourceAtmosMeta.getWsChecksum() != null) { AtmosConfig.Hash checksumType = AtmosConfig.Hash.valueOf(sourceAtmosMeta.getWsChecksum().getAlgorithm().toString().toLowerCase()); request.setContentLength(object.getMetadata().getContentLength()); if (config.isPreserveObjectId()) request.setCustomObjectId(object.getRelativePath()); targetOid = time(new Function<ObjectId>() { @Override if (config.isPreserveObjectId()) { if (object.getRelativePath().equals(targetOid.getId())) { log.debug("object ID {} successfully preserved in target", object.getRelativePath());
@Override public void updateObject(String identifier, SyncObject object) { ObjectIdentifier targetId = config.getAccessType() == namespace ? new ObjectPath(identifier) : new ObjectId(identifier); com.emc.atmos.api.bean.ObjectMetadata sourceAtmosMeta = (com.emc.atmos.api.bean.ObjectMetadata) object.getProperty(PROP_ATMOS_METADATA); if (config.getWsChecksumType() != null || (sourceAtmosMeta != null && sourceAtmosMeta.getWsChecksum() != null)) { AtmosConfig.Hash checksumType = config.getWsChecksumType(); if (checksumType == null) checksumType = AtmosConfig.Hash.valueOf(sourceAtmosMeta.getWsChecksum().getAlgorithm().toString().toLowerCase()); if (config.isReplaceMetadata()) deleteUserMeta(targetId);
@Override public String getRelativePath(String identifier, boolean directory) { if (config.getAccessType() == objectspace) { return identifier; } else { String rootPath = rootSummary.getIdentifier(); String relativePath = identifier; if (identifier.startsWith(rootPath)) relativePath = identifier.substring(rootPath.length()); // remove leading and trailing slashes from relative path if (relativePath.startsWith("/")) relativePath = relativePath.substring(1); if (relativePath.endsWith("/")) relativePath = relativePath.substring(0, relativePath.length() - 1); return relativePath; } }
cRequest.contentType(obj.getMetadata().getContentType()).setUserMetadata(atmosMeta.values()); if (config.isPreserveObjectId()) cRequest.setCustomObjectId(obj.getRelativePath()); if (config.isRetentionEnabled()) { com.emc.atmos.api.bean.ObjectMetadata sourceAtmosMeta = (com.emc.atmos.api.bean.ObjectMetadata) obj.getProperty(PROP_ATMOS_METADATA); if (sourceAtmosMeta.getWsChecksum() == null)
@Override public void delete(final String identifier) { if (config.isRemoveTagsOnDelete()) {
private ObjectIdentifier getObjectIdentifier(String identifier) { switch (config.getAccessType()) { case namespace: return new ObjectPath(identifier); case objectspace: default: return new ObjectId(identifier); } }
@Override public String getIdentifier(String relativePath, boolean directory) { if (config.getAccessType() == objectspace) { return relativePath; } else { if (!rootSummary.isDirectory() && relativePath != null && relativePath.length() > 0) throw new RuntimeException("target path is a file, but source is a directory"); // start with path in configuration String rootPath = rootSummary.getIdentifier(); if (relativePath == null) relativePath = ""; // shouldn't happen // remove leading slashes from relative path (there shouldn't be any though) if (relativePath.startsWith("/")) relativePath = relativePath.substring(1); // add trailing slash for directories if (directory) relativePath += "/"; // concatenate return rootPath + relativePath; } }
@Override public void configure(SyncStorage source, Iterator<SyncFilter> filters, SyncStorage target) { super.configure(source, filters, target); // The target must be an AtmosTarget plugin configured in // object space mode. if (!(target instanceof AtmosStorage)) { throw new ConfigurationException("This plugin is only compatible with Atmos Targets"); } if (((AtmosStorage) target).getConfig().getAccessType() != AtmosConfig.AccessType.objectspace) { throw new ConfigurationException("When using the Gladinet plugin, the Atmos Target must be in object mode, not namespace mode."); } this.targetAtmos = ((AtmosStorage) target).getAtmos(); if (baseDir == null) baseDir = ""; baseDir = baseDir.replace('\\', '/'); // Normalize it so it doesn't contain leading or trailing // slashes if (baseDir.startsWith("/")) { baseDir = baseDir.substring(1); } if (baseDir.endsWith("/")) { baseDir = baseDir.substring(0, baseDir.length() - 1); } // If a root directory was specified, make sure it exists if (!baseDir.isEmpty()) { String tag = getTag(baseDir); if (tag == null) { throw new ConfigurationException("The Gladinet base directory " + baseDir + " does not exist"); } } }
@Override public SyncObject loadObject(final String identifier) throws ObjectNotFoundException { if (identifier == null) throw new ObjectNotFoundException(); try { if (config.getAccessType() == objectspace && !validObjectId(identifier)) throw new ObjectNotFoundException(identifier); ObjectIdentifier id = getObjectIdentifier(identifier); final com.emc.atmos.api.bean.ObjectMetadata atmosMeta = getAtmosMetadata(id); ObjectMetadata metadata = getSyncMeta(id, atmosMeta); Metadata uidMeta = atmosMeta.getMetadata().get(UID_PROP); String uid = uidMeta == null ? null : uidMeta.getValue(); ObjectAcl acl = getSyncAcl(uid, atmosMeta.getAcl()); LazyValue<InputStream> lazyStream = new LazyValue<InputStream>() { @Override public InputStream get() { return readDataStream(identifier); } }; SyncObject object = new SyncObject(this, getRelativePath(identifier, metadata.isDirectory()), metadata).withAcl(acl) .withLazyStream(lazyStream); object.setProperty(PROP_ATMOS_METADATA, atmosMeta); return object; } catch (AtmosException e) { if (e.getHttpCode() == 404) throw new ObjectNotFoundException(identifier, e); throw e; } }