OSResourceManager.java
/*
** Module : OSResourceManager.java
** Abstract : Management of OS resources, which can be allocated on client or server side.
**
** Copyright (c) 2022-2025, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------------Description----------------------------------------
** 001 CA 20220515 Created initial version.
** CA 20220918 Allow legacy client sockets to be ran on FWD server instead of FWD client.
** 002 HC 20230427 Implemented server-side file-system resource. File operations performed on
** client can be optionally performed directly on server without the expensive
** remote call.
** 003 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
** 004 HC 20230517 Implemented server-side web service calling.
** 005 GBB 20240826 Moving to osresource package. Replacing type string constraints with enum.
** Removing the once per JVM init mechanism (moved to concrete classes).
** Adding static getters for resources.
** 006 GBB 20240912 Adding support for types mail, launcher and streams. Implicitly enabling related types.
** Using enum instead of listing each type, allows for easily extending with new types.
** 007 GBB 20250403 Adding isAllServerSide for when 'all' is specified in server-side-resources.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.util.osresource;
import java.util.*;
import java.util.logging.*;
import com.goldencode.p2j.directory.*;
import com.goldencode.p2j.library.*;
import com.goldencode.p2j.net.SessionManager;
import com.goldencode.p2j.security.*;
import com.goldencode.p2j.util.*;
import com.goldencode.p2j.util.logging.*;
/**
* Allows configuration of OS resources like {@link memptr} or {@link NativeInvoker library}, to be remoted
* either from the server or client-side.
* <p>
* Server-side resources can be enabled via a directory configuration, per account, group, server or global.
* The directory node is:
* <pre>
* <node class="string" name="server-side-resources">
* <node-attribute name="value" value="memptr,library,streams">
* </node>
* </pre>
* <p>
* The special value <code>all</code> can be used to enable all OS resources at server-side, to not specify
* them by name.
*/
public abstract class OSResourceManager
{
/** Logger. */
protected static final CentralLogger LOG = CentralLogger.get(OSResourceManager.class.getName());
/** The OS resource manager singleton (client or server side). */
private static ContextLocal<OSResourceManager> mgr = new ContextLocal<OSResourceManager>()
{
protected OSResourceManager initialValue()
{
boolean client = SessionManager.get().isLeaf();
return client ? new ClientResourceManager() : new ServerResourceManager();
};
};
/** Map with flags for each server-side enabled OS resource. */
private final Map<OsResourceType, Boolean> serverSideResources = new HashMap<>();
/** All OS resources are enabled server-side. */
private final boolean IS_ALL_SERVER_SIDE;
/** The remote objects, either network or local, depending on how the OS resource is configured. */
final Map<OsResourceType, Object> resources = new HashMap<>();
/**
* Initialize this instance with the current context's server-side resource configuration.
*/
public OSResourceManager()
{
Directory dir = DirectoryManager.getInstance();
String res = dir.getString(Directory.ID_RELATIVE_BOTH, "server-side-resources", "");
// lowercase the string, to match the case of the resource name constants
res = res.toLowerCase();
Collection<OsResourceType> osResources = new HashSet<>();
IS_ALL_SERVER_SIDE =
osResources.contains(OsResourceType.ALL) || OsResourceType.ALL.getName().equals(res);
Arrays.stream(OsResourceType.values())
.filter(type -> type.getName() != null)
.forEach(type -> serverSideResources.put(type, IS_ALL_SERVER_SIDE));
if (IS_ALL_SERVER_SIDE)
{
return;
}
osResources.forEach(type -> serverSideResources.put(type, Boolean.TRUE));
for (String resName : res.split(","))
{
resName = resName.trim();
if (resName.isEmpty())
{
continue;
}
OsResourceType resType = OsResourceType.find(resName);
if (resType == null)
{
continue;
}
if (!serverSideResources.containsKey(resType))
{
if (LOG.isLoggable(Level.WARNING))
{
LOG.log(Level.WARNING, "Failed configuring server-side resource: '" + resName +
"' is not a valid name.");
}
continue;
}
serverSideResources.put(resType, Boolean.TRUE);
}
if (isServerSide(OsResourceType.ENVIRONMENTS) && !isServerSide(OsResourceType.FILESYSTEM))
{
LOG.warning("!!! Implicitly enabling server-side filesystem !!! Server-side 'environments' enabled.");
serverSideResources.put(OsResourceType.FILESYSTEM, Boolean.TRUE);
}
if (isServerSide(OsResourceType.FILESYSTEM) && !isServerSide(OsResourceType.STREAMS))
{
LOG.warning("!!! Implicitly enabling server-side streams !!! Server-side 'filesystem' enabled.");
serverSideResources.put(OsResourceType.STREAMS, Boolean.TRUE);
}
else if (!isServerSide(OsResourceType.FILESYSTEM) && isServerSide(OsResourceType.STREAMS))
{
LOG.warning("!!! Implicitly enabling server-side filesystem !!! Server-side 'streams' enabled.");
serverSideResources.put(OsResourceType.FILESYSTEM, Boolean.TRUE);
}
}
/**
* Get the OS resource manager instance.
*
* @return See above.
*/
public static OSResourceManager getInstance()
{
return mgr.get();
}
/**
* Initialize the OS {@link OsResourceType#MEMPTR} resource.
*
* @return The {@link LowLevelBuffer} network or local object.
*/
public static LowLevelBuffer getMemptr()
{
return mgr.get().initializeMemptr();
}
/**
* Initialize the OS {@link OsResourceType#LIBRARY} resource.
*
* @return The {@link NativeAPICaller} network or local object.
*/
public static NativeAPICaller getLibrary()
{
return mgr.get().initializeLibrary();
}
/**
* Initialize the OS {@link OsResourceType#SOCKET} resource.
*
* @return The {@link LowLevelSocket} network or local object.
*/
public static LowLevelSocket getSocket()
{
return mgr.get().initializeSocket();
}
/**
* Initialize the OS {@link OsResourceType#FILESYSTEM} resource.
*
* @return The {@link FileSystem} network or local object.
*/
public static FileSystem getFileSystem()
{
return mgr.get().initializeFileSystem();
}
/**
* Initialize the OS {@link OsResourceType#WEBSERVICE} resource.
*
* @return The {@link WebService} network or local object.
*/
public static WebService getWebService()
{
return mgr.get().initializeWebService();
}
/**
* Get the OS {@link OsResourceType#ENVIRONMENTS} resource.
*
* @return The {@link EnvironmentAccessor} network or local object.
*/
public static EnvironmentAccessor getEnvironments()
{
return mgr.get().initializeEnvironments();
}
/**
* Get the OS {@link OsResourceType#MAIL} resource.
*
* @return The {@link RemoteEmailSender} network or local object.
*/
public static RemoteEmailSender getEmailSender()
{
return mgr.get().initializeEmailSender();
}
/**
* Get the OS {@link OsResourceType#LAUNCHER} resource.
*
* @return The {@link Launcher} network or local object.
*/
public static Launcher getProcessLauncher()
{
return mgr.get().initializeProcessLauncher();
}
/**
* Get the OS {@link OsResourceType#STREAMS} resource.
*
* @return The {@link StreamDaemon} network or local object.
*/
public static StreamHelper getStreamHelper()
{
return mgr.get().initializeStreamHelper();
}
/**
* Returns <code>true</code> if all OS resources are enabled server-side.
*
* @return See above.
*/
public boolean isAllServerSide()
{
return IS_ALL_SERVER_SIDE;
}
/**
* Check if the resource type is enabled on the server side.
*
* @return See above.
*/
public boolean isServerSide(OsResourceType type)
{
return serverSideResources.get(type);
}
/**
* Initialize the OS {@link OsResourceType#MEMPTR} resource.
*
* @return The {@link LowLevelBuffer} network or local object.
*/
abstract LowLevelBuffer initializeMemptr();
/**
* Initialize the OS {@link OsResourceType#LIBRARY} resource.
*
* @return The {@link NativeAPICaller} network or local object.
*/
abstract NativeAPICaller initializeLibrary();
/**
* Initialize the OS {@link OsResourceType#SOCKET} resource.
*
* @return The {@link LowLevelSocket} network or local object.
*/
abstract LowLevelSocket initializeSocket();
/**
* Initialize the OS {@link OsResourceType#FILESYSTEM} resource.
*
* @return The {@link FileSystem} network or local object.
*/
abstract FileSystem initializeFileSystem();
/**
* Initialize the OS {@link OsResourceType#WEBSERVICE} resource.
*
* @return The {@link WebService} network or local object.
*/
abstract WebService initializeWebService();
/**
* Initialize the OS {@link OsResourceType#ENVIRONMENTS} resource.
*
* @return The {@link EnvironmentAccessor} network or local object.
*/
abstract EnvironmentAccessor initializeEnvironments();
/**
* Initialize the OS {@link OsResourceType#MAIL} resource.
*
* @return The {@link RemoteEmailSender} network or local object.
*/
abstract RemoteEmailSender initializeEmailSender();
/**
* Initialize the OS {@link OsResourceType#LAUNCHER} resource.
*
* @return The {@link Launcher} network or local object.
*/
abstract Launcher initializeProcessLauncher();
/**
* Initialize the OS {@link OsResourceType#STREAMS} resource.
*
* @return The {@link StreamDaemon} network or local object.
*/
abstract StreamHelper initializeStreamHelper();
}