From a4e2def61f587de89a03037aec2b95c54732ec55 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Thu, 22 Dec 2022 11:09:07 +0100 Subject: [PATCH] Adapt to MS Windows --- .../src/org/argeo/cms/dbus/CmsDBusImpl.java | 23 ++++++++---- .../src/org/argeo/cms/acr/fs/FsContent.java | 14 ++++---- .../argeo/cms/acr/fs/FsContentProvider.java | 35 +++++++++++++++++-- .../cms/internal/runtime/CmsStateImpl.java | 4 ++- .../runtime/DeployedContentRepository.java | 6 ++-- 5 files changed, 64 insertions(+), 18 deletions(-) diff --git a/org.argeo.cms.lib.dbus/src/org/argeo/cms/dbus/CmsDBusImpl.java b/org.argeo.cms.lib.dbus/src/org/argeo/cms/dbus/CmsDBusImpl.java index b9a202be9..cf939648a 100644 --- a/org.argeo.cms.lib.dbus/src/org/argeo/cms/dbus/CmsDBusImpl.java +++ b/org.argeo.cms.lib.dbus/src/org/argeo/cms/dbus/CmsDBusImpl.java @@ -19,6 +19,7 @@ public class CmsDBusImpl implements CmsDBus { private BusAddress sessionBusAddress; private EmbeddedDBusDaemon dBusDaemon; + private Path dBusDaemonSocket; private CmsEventBus cmsEventBus; @@ -27,8 +28,9 @@ public class CmsDBusImpl implements CmsDBus { final String envSessionBusAddress = System.getenv(DBUS_SESSION_BUS_ADDRESS); if (envSessionBusAddress != null) { sessionBusAddress = BusAddress.of(envSessionBusAddress); - - // !! We must first initialise a connection, otherwise there are classloader issues later on + + // !! We must first initialise a connection, otherwise there are classloader + // issues later on try (DBusConnection dBusConnection = DBusConnectionBuilder.forAddress(sessionBusAddress) .withShared(false).build()) { @@ -36,11 +38,15 @@ public class CmsDBusImpl implements CmsDBus { log.debug(() -> "Found session DBus with address " + sessionBusAddress); } else { Path socketLocation = Paths.get(System.getProperty("user.home"), ".cache", "argeo", "bus"); - Files.createDirectories(socketLocation.getParent()); - // TODO escape : on Windows? - String embeddedSessionBusAddress = "unix:path=" + socketLocation.toUri().getPath(); - dBusDaemon = new EmbeddedDBusDaemon(embeddedSessionBusAddress); + if (Files.exists(socketLocation)) + Files.delete(socketLocation); + else + Files.createDirectories(socketLocation.getParent()); + + String embeddedSessionBusAddress = "unix:path=" + socketLocation.toString(); + dBusDaemon = new EmbeddedDBusDaemon(embeddedSessionBusAddress + ",listen=true"); dBusDaemon.startInBackgroundAndWait(30 * 1000); + dBusDaemonSocket = socketLocation; sessionBusAddress = BusAddress.of(embeddedSessionBusAddress); try (DBusConnection dBusConnection = DBusConnectionBuilder.forAddress(sessionBusAddress) @@ -63,6 +69,11 @@ public class CmsDBusImpl implements CmsDBus { } catch (IOException e) { log.error("Cannot close embedded DBus daemon", e); } + try { + Files.delete(dBusDaemonSocket); + } catch (IOException e) { + log.error("Cannot delete DBus daemon socket " + dBusDaemonSocket, e); + } } } diff --git a/org.argeo.cms/src/org/argeo/cms/acr/fs/FsContent.java b/org.argeo.cms/src/org/argeo/cms/acr/fs/FsContent.java index 43cae8572..5920c4203 100644 --- a/org.argeo.cms/src/org/argeo/cms/acr/fs/FsContent.java +++ b/org.argeo.cms/src/org/argeo/cms/acr/fs/FsContent.java @@ -90,7 +90,7 @@ public class FsContent extends AbstractContent implements ProvidedContent { } else { // TODO should we support prefixed name for known types? - QName providerName = NamespaceUtils.parsePrefixedName(provider, path.getFileName().toString()); + QName providerName = provider.fromFsPrefixedName(path.getFileName().toString()); // QName providerName = new QName(path.getFileName().toString()); // TODO remove extension if mounted? this.name = new ContentName(providerName, session); @@ -126,7 +126,7 @@ public class FsContent extends AbstractContent implements ProvidedContent { } else { UserDefinedFileAttributeView udfav = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class); - String prefixedName = NamespaceUtils.toPrefixedName(provider, key); + String prefixedName = provider.toFsPrefixedName(key); if (!udfav.list().contains(prefixedName)) return Optional.empty(); ByteBuffer buf = ByteBuffer.allocate(udfav.size(prefixedName)); @@ -198,7 +198,7 @@ public class FsContent extends AbstractContent implements ProvidedContent { if (udfav != null) { try { for (String name : udfav.list()) { - QName providerName = NamespaceUtils.parsePrefixedName(provider, name); + QName providerName = provider.fromFsPrefixedName(name); if (providerName.getNamespaceURI().equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) continue; // skip prefix mapping QName sessionName = new ContentName(providerName, getSession()); @@ -215,7 +215,7 @@ public class FsContent extends AbstractContent implements ProvidedContent { protected void removeAttr(QName key) { UserDefinedFileAttributeView udfav = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class); try { - udfav.delete(NamespaceUtils.toPrefixedName(provider, key)); + udfav.delete(provider.toFsPrefixedName(key)); } catch (IOException e) { throw new ContentResourceException("Cannot delete attribute " + key + " for " + path, e); } @@ -239,7 +239,7 @@ public class FsContent extends AbstractContent implements ProvidedContent { UserDefinedFileAttributeView udfav = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class); ByteBuffer bb = ByteBuffer.wrap(toWrite.getBytes(StandardCharsets.UTF_8)); try { - udfav.write(NamespaceUtils.toPrefixedName(provider, key), bb); + udfav.write(provider.toFsPrefixedName(key), bb); } catch (IOException e) { throw new ContentResourceException("Cannot delete attribute " + key + " for " + path, e); } @@ -250,7 +250,7 @@ public class FsContent extends AbstractContent implements ProvidedContent { if (POSIX_KEYS.containsKey(key)) return POSIX_KEYS.get(key); else - return USER_ + NamespaceUtils.toPrefixedName(provider, key); + return USER_ + provider.toFsPrefixedName(key); } /* @@ -285,7 +285,7 @@ public class FsContent extends AbstractContent implements ProvidedContent { public Content add(QName name, QName... classes) { FsContent fsContent; try { - Path newPath = path.resolve(NamespaceUtils.toPrefixedName(provider, name)); + Path newPath = path.resolve(provider.toFsPrefixedName(name)); if (ContentName.contains(classes, DName.collection.qName())) Files.createDirectory(newPath); else diff --git a/org.argeo.cms/src/org/argeo/cms/acr/fs/FsContentProvider.java b/org.argeo.cms/src/org/argeo/cms/acr/fs/FsContentProvider.java index 9b1b96683..47cd64af3 100644 --- a/org.argeo.cms/src/org/argeo/cms/acr/fs/FsContentProvider.java +++ b/org.argeo.cms/src/org/argeo/cms/acr/fs/FsContentProvider.java @@ -13,6 +13,8 @@ import java.util.Objects; import java.util.TreeMap; import java.util.stream.Collectors; +import javax.xml.namespace.QName; + import org.argeo.api.acr.ArgeoNamespace; import org.argeo.api.acr.ContentResourceException; import org.argeo.api.acr.NamespaceUtils; @@ -20,28 +22,36 @@ import org.argeo.api.acr.RuntimeNamespaceContext; import org.argeo.api.acr.spi.ContentProvider; import org.argeo.api.acr.spi.ProvidedContent; import org.argeo.api.acr.spi.ProvidedSession; +import org.argeo.cms.util.OS; /** Access a file system as a {@link ContentProvider}. */ public class FsContentProvider implements ContentProvider { - final static String XMLNS_ = "xmlns:"; protected String mountPath; protected Path rootPath; private NavigableMap prefixes = new TreeMap<>(); + private final boolean isNtfs; + private final String XMLNS_; + public FsContentProvider(String mountPath, Path rootPath) { Objects.requireNonNull(mountPath); Objects.requireNonNull(rootPath); this.mountPath = mountPath; this.rootPath = rootPath; + + this.isNtfs = OS.LOCAL.isMSWindows(); + this.XMLNS_ = isNtfs ? "xmlns%3A" : "xmlns:"; + // FIXME make it more robust initNamespaces(); } protected FsContentProvider() { - + this.isNtfs = OS.LOCAL.isMSWindows(); + this.XMLNS_ = isNtfs ? "xmlns%3A" : "xmlns:"; } protected void initNamespaces() { @@ -117,6 +127,27 @@ public class FsContentProvider implements ContentProvider { return Files.exists(rootPath.resolve(relativePath)); } + /* + * ATTRIBUTE NAMES + */ + /** + * Make sure that the prefixed name is compatible with the underlying file + * system for file names/attributes (NTFS does not accept :) + */ + String toFsPrefixedName(QName key) { + return isNtfs ? NamespaceUtils.toPrefixedName(this, key).replace(":", "%3A") + : NamespaceUtils.toPrefixedName(this, key); + } + + /** + * PArse a prefixed name which is compatible with the underlying file system for + * file names/attributes (NTFS does not accept :) + */ + QName fromFsPrefixedName(String name) { + return isNtfs ? NamespaceUtils.parsePrefixedName(this, name.replace("%3A", ":")) + : NamespaceUtils.parsePrefixedName(this, name); + } + /* * NAMESPACE CONTEXT */ diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java index d364620f5..c1f92deb4 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java @@ -39,6 +39,7 @@ import org.argeo.api.uuid.UuidFactory; import org.argeo.cms.CmsDeployProperty; import org.argeo.cms.auth.ident.IdentClient; import org.argeo.cms.util.FsUtils; +import org.argeo.cms.util.OS; /** * Implementation of a {@link CmsState}, initialising the required services. @@ -168,7 +169,8 @@ public class CmsStateImpl implements CmsState { try { if (!Files.exists(privateDir)) Files.createDirectories(privateDir); - Files.setPosixFilePermissions(privateDir, posixPermissions); + if (!OS.LOCAL.isMSWindows()) + Files.setPosixFilePermissions(privateDir, posixPermissions); } catch (IOException e) { log.error("Cannot set permissions on " + privateDir, e); } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/DeployedContentRepository.java b/org.argeo.cms/src/org/argeo/cms/internal/runtime/DeployedContentRepository.java index 0fd0a63ed..bb1f6112a 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/runtime/DeployedContentRepository.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/runtime/DeployedContentRepository.java @@ -9,9 +9,10 @@ import org.argeo.api.cms.directory.CmsUserManager; import org.argeo.cms.acr.CmsContentRepository; import org.argeo.cms.acr.directory.DirectoryContentProvider; import org.argeo.cms.acr.fs.FsContentProvider; +import org.argeo.cms.util.OS; public class DeployedContentRepository extends CmsContentRepository { - private final static String ROOT_XML = "cr:root.xml"; + private final static String ROOT_XML = OS.LOCAL.isMSWindows() ? "cr%3Aroot.xml" : "cr:root.xml"; private final static CmsLog log = CmsLog.getLog(DeployedContentRepository.class); @@ -22,7 +23,8 @@ public class DeployedContentRepository extends CmsContentRepository { long begin = System.currentTimeMillis(); try { super.start(); - Path rootXml = KernelUtils.getOsgiInstancePath(ROOT_XML); + // FIXME does not work on Windows + //Path rootXml = KernelUtils.getOsgiInstancePath(ROOT_XML); initRootContentProvider(null); // Path srvPath = KernelUtils.getOsgiInstancePath(CmsConstants.SRV_WORKSPACE); -- 2.30.2