diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 64c94a1..77571b6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,6 +38,10 @@ jobs: run: dotnet pack src/Fdc3.NewtonsoftJson/MorganStanley.Fdc3.NewtonsoftJson.csproj --no-build --configuration Release --output packages + - name: Pack Fdc3.AppDirectory + run: + dotnet pack src/Fdc3.AppDirectory/MorganStanley.Fdc3.AppDirectory.csproj --no-build --configuration Release --output packages + - name: Upload uses: actions/upload-artifact@v3 with: diff --git a/src/Fdc3.AppDirectory/AppChannel.cs b/src/Fdc3.AppDirectory/AppChannel.cs new file mode 100644 index 0000000..4167884 --- /dev/null +++ b/src/Fdc3.AppDirectory/AppChannel.cs @@ -0,0 +1,57 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. 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. + */ + +using System; +using System.Collections.Generic; + +namespace MorganStanley.Fdc3.AppDirectory +{ + /// + /// Describes the application's use of App Channels. + /// This metadata is not currently used by the desktop agent, but is provided + /// to help find apps that will interoperate with this app and to document API + /// interactions for use by other app developers. + /// + public class AppChannel + { + /// + /// Initializes a new instance of the class. + /// + /// The name + /// Exception if name is null + public AppChannel(string name) + { + Name = name ?? throw new ArgumentNullException(nameof(name)); + } + /// + /// The name of the App Channel. + /// + public string Name { get; set; } + + /// + /// A description of how the channel is used. + /// + public string? Description { get; set; } + + /// + /// Context type names that are broadcast by the application on the channel. + /// + public IEnumerable? Broadcasts { get; set; } + + /// + /// Context type names that the application listens for on the channel. + /// + public IEnumerable? ListensFor { get; set; } + } +} diff --git a/src/Fdc3.AppDirectory/AppDetails/CitrixAppDetails.cs b/src/Fdc3.AppDirectory/AppDetails/CitrixAppDetails.cs new file mode 100644 index 0000000..952c160 --- /dev/null +++ b/src/Fdc3.AppDirectory/AppDetails/CitrixAppDetails.cs @@ -0,0 +1,46 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. 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. + */ + +using System; + +namespace MorganStanley.Fdc3.AppDirectory +{ + /// + /// App virtualized via Citrix. + /// + public class CitrixAppDetails + { + /// + /// Initializes a new instance of the class. + /// + /// The alias + /// The arguments + /// Exception if the alias is null + public CitrixAppDetails(string alias, string? arguments) + { + Alias = alias ?? throw new ArgumentNullException(nameof(alias)); + Arguments = arguments; + } + + /// + /// The Citrix alias / name of the virtual app (passed to the Citrix SelfService qlaunch parameter). + /// + public string Alias { get; set; } + + /// + /// Arguments that must be passed on the command line to launch the app in the expected configuration. + /// + public string? Arguments { get; set; } + } +} diff --git a/src/Fdc3.AppDirectory/AppDetails/NativeAppDetails.cs b/src/Fdc3.AppDirectory/AppDetails/NativeAppDetails.cs new file mode 100644 index 0000000..2fadf2c --- /dev/null +++ b/src/Fdc3.AppDirectory/AppDetails/NativeAppDetails.cs @@ -0,0 +1,45 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. 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. + */ + +using System; + +namespace MorganStanley.Fdc3.AppDirectory +{ + /// + /// Native application pre-installed on a device and launch via a filesystem path. + /// + public class NativeAppDetails + { + /// + /// Initializes a new instance of the class. + /// + /// The path + /// The arguments + /// Exception if the path is null + public NativeAppDetails(string path, string? arguments) + { + Path = path ?? throw new ArgumentNullException(nameof(path)); + Arguments = arguments; + } + /// + /// The path on disk from which the application is launched. + /// + public string Path { get; set; } + + /// + /// Arguments that must be passed on the command line to launch the app in the expected configuration. + /// + public string? Arguments { get; set; } + } +} diff --git a/src/Fdc3.AppDirectory/AppDetails/OnlineNativeAppDetails.cs b/src/Fdc3.AppDirectory/AppDetails/OnlineNativeAppDetails.cs new file mode 100644 index 0000000..d1b3a01 --- /dev/null +++ b/src/Fdc3.AppDirectory/AppDetails/OnlineNativeAppDetails.cs @@ -0,0 +1,38 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. 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. + */ + +using System; + +namespace MorganStanley.Fdc3.AppDirectory +{ + /// + /// Native app that have an online launcher, e.g. online ClickOnce app deployments. + /// + public class OnlineNativeAppDetails + { + /// + /// Initializes a new instance of the class. + /// + /// The url + /// Exception if the url is null + public OnlineNativeAppDetails(string url) + { + Url = url ?? throw new ArgumentNullException(nameof(url)); + } + /// + /// Application URL. + /// + public string Url { get; set; } + } +} diff --git a/src/Fdc3.AppDirectory/AppDetails/WebAppDetails.cs b/src/Fdc3.AppDirectory/AppDetails/WebAppDetails.cs new file mode 100644 index 0000000..75e47b5 --- /dev/null +++ b/src/Fdc3.AppDirectory/AppDetails/WebAppDetails.cs @@ -0,0 +1,40 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. 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. + */ + +using System; + +namespace MorganStanley.Fdc3.AppDirectory +{ + /// + /// Web application launched via a URL. + /// + public class WebAppDetails + { + /// + /// Initializes a new instance of the class. + /// + /// The url + /// Exception if the url is null + public WebAppDetails(string url) + { + Url = url ?? throw new ArgumentNullException(nameof(url)); + } + + /// + /// + /// Application start URL. + /// + public string Url { get; set; } + } +} diff --git a/src/Fdc3.AppDirectory/AppType.cs b/src/Fdc3.AppDirectory/AppType.cs new file mode 100644 index 0000000..695c911 --- /dev/null +++ b/src/Fdc3.AppDirectory/AppType.cs @@ -0,0 +1,28 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. 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. + */ + +namespace MorganStanley.Fdc3.AppDirectory +{ + /// + /// FDC3 application types + /// + public enum AppType + { + Other, + Web, + Native, + Citrix, + OnlineNative + } +} diff --git a/src/Fdc3.AppDirectory/Fdc3App.cs b/src/Fdc3.AppDirectory/Fdc3App.cs new file mode 100644 index 0000000..a63897f --- /dev/null +++ b/src/Fdc3.AppDirectory/Fdc3App.cs @@ -0,0 +1,194 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. 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. + */ + +using System; +using System.Collections.Generic; + +namespace MorganStanley.Fdc3.AppDirectory +{ + /// + /// Defines an application retrieved from an FDC3 App Directory, which can then be launched. + /// Launching typically means running for a user on a desktop. The details around 'launching' including + /// who or what might do it, and how the launch action is initiated are discussed elsewhere in the FDC3 + /// App Directory spec. + /// + public class Fdc3App + { + public Fdc3App(string appId, string name, AppType type, object details) + { + AppId = appId ?? throw new ArgumentNullException(nameof(appId)); + Name = name ?? throw new ArgumentNullException( nameof(name)); + Type = type; + Details = details ?? throw new ArgumentNullException(nameof(details)); + } + /// + /// The unique application identifier located within a specific application directory instance. + /// + public string AppId { get; set; } + + /// + /// The name of the application. The name should be unique within an FDC3 App Directory instance. + /// The exception to the uniqueness constraint is that an App Directory can hold definitions + /// for multiple versions of the same app. The same appName could occur in other directories. + /// We are not currently specifying app name conventions in the document. + /// + public string Name { get; set; } + + /// + /// The technology type that is used to launch and run the application. + /// Each application type implies a particular set of launch details. The supported types include: + /// + /// + /// web: Web applications launched via a URL + /// + /// + /// native: Native applications pre-installed on a device and launch via a filesystem path + /// + /// + /// citrix: Apps virtualized via Citrix + /// + /// + /// onlineNative: Native apps that have an online launcher, e.g.online ClickOnce app deployments. + /// + /// + /// other: Used to represent apps that do not conform to or cannot be launched via the other types, + /// and are likely to be defined solely by a hostManifest. + /// + /// + /// FDC3 Desktop Agents MUST support at least the web application type and MAY support any or all of the other types. + /// + public AppType Type { get; set; } + + /// + /// The type specific launch details of the application. These details are intended to be vendor-agnostic + /// and MAY be duplicated or overridden by details provided in the hostManifests object for a specific host. + /// + public object Details { get; set; } + + /// + /// Version of the application. This allows multiple app versions to be defined using the same app name. + /// This can be a triplet but can also include things like 1.2.5 (BETA) + /// + public string? Version { get; set; } + + /// + /// Optional title for the application, if missing use appName, typically used in a launcher UI. + /// + public string? Title { get; set; } + + /// + /// Optional tooltip description e.g. for a launcher + /// + public string? ToolTip { get; set; } + + /// + /// Description of the application. This will typically be a 1-2 paragraph style blurb about the application. + /// + public string? Description { get; set; } + + /// + /// An array of string categories that describe the application.These are meant as a hint to catalogs or stores + /// listing FDC3-enabled apps and it is expected that these will make a best effort to find appropriate categories (or category) + /// under which to list the app.AppD record authors are encouraged to use lower-case and, where possible, + /// to select categories from the following list: allocations, analytics, charts, chat,communication, + /// compliance, crm, developer tools, events, execution management, file sharing, market data, news + /// networking, office apps, order management, other, portfolio management, presentation, pricing + /// productivity, research, risk, screen sharing, security, spreadsheet, trade cost analysis + /// trading system, training, travel, video, visualization, weather + /// + public IEnumerable? Categories { get; set; } + + /// + /// A language tag that specifies the primary language of both the application and its AppD entry, as defined by IETF RFC 5646. + /// + public string? Lang { get; set; } + + /// + /// Holds Icons used for the application, a Launcher may be able to use multiple Icon sizes or there may be a 'button' Icon + /// + public IEnumerable? Icons { get; set; } + + /// + /// Array of images to show the user when they are looking at app description. Each image can have an optional description/tooltip + /// + public IEnumerable? Screenshots { get; set; } + + /// + /// Optional e-mail to receive queries about the application + /// + public string? ContactEmail { get; set; } + + /// + /// Optional e-mail to receive support requests for the application + /// + public string? SupportEmail { get; set; } + + /// + /// Optional URL that provides more information about the application + /// + public string? MoreInfo { get; set; } + + /// + /// The name of the company that owns the application. The publisher has control over their namespace/app/signature. + /// + public string? Publisher { get; set; } + + /// + /// An optional set of name value pairs that can be used to deliver custom data from an App Directory to a launcher. + /// + public Dictionary? CustomConfig { get; set; } + + /// + /// + /// + public Dictionary? HostManifests { get; set; } + + /// + /// + /// + public Interop? Interop { get; set; } + + /// + /// Provides localized alternatives to any field of the AppD record, which may also refer to an alternative + /// version of the application that is also localized (e.g. by providing customConfig or an alternative URL). + /// The keys to this object should be language tags as defined by IETF RFC 5646, e.g. en, en-GB or fr-FR. + /// + public Dictionary? LocalizedVersions { get; set; } + } + + /// + /// Represents an FDC3 application with specific details of type . + /// + /// The type of application details. + public class Fdc3App : Fdc3App where TDetails : class + { + /// + /// Initializes a new instance of the class. + /// + /// The application ID. + /// The application name. + /// The application type. + /// The application details of type . + public Fdc3App(string appId, string name, AppType type, TDetails details) : base(appId, name, type, details) + { + } + + /// + public new TDetails Details + { + get => base.Details as TDetails ?? throw new InvalidCastException($"Cannot cast base.Details to {typeof(TDetails)}"); + set => base.Details = value; + } + } +} diff --git a/src/Fdc3.AppDirectory/IAppDirectory.cs b/src/Fdc3.AppDirectory/IAppDirectory.cs new file mode 100644 index 0000000..b0f8e06 --- /dev/null +++ b/src/Fdc3.AppDirectory/IAppDirectory.cs @@ -0,0 +1,38 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. 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. + */ + +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace MorganStanley.Fdc3.AppDirectory +{ + /// + /// Interface definition for the AppDirectory. + /// + public interface IAppDirectory + { + /// + /// Returns a list of all applications from the AppDirectory. + /// + /// List of applications. + Task> GetApps(); + + /// + /// Returns an application by appId from the AppDirectory. + /// + /// Application identifier + /// The application + Task GetApp(string appId); + } +} diff --git a/src/Fdc3.AppDirectory/IntentMetadata.cs b/src/Fdc3.AppDirectory/IntentMetadata.cs new file mode 100644 index 0000000..6618726 --- /dev/null +++ b/src/Fdc3.AppDirectory/IntentMetadata.cs @@ -0,0 +1,69 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. 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. + */ + +using System; +using System.Collections.Generic; + +namespace MorganStanley.Fdc3.AppDirectory +{ + /// + /// Implementation of + /// + public class IntentMetadata : IIntentMetadata + { + /// + /// Initializes a new instance of the class. + /// + /// The name + /// The displayName + /// The contexts + /// Exception contexts is null + public IntentMetadata(string name, string displayName, IEnumerable contexts) + { + Name = name; + DisplayName = displayName; + Contexts = contexts ?? throw new ArgumentNullException(nameof(contexts)); + } + + /// + /// Definition of an intent that an app listens for + /// + public string Name { get; set; } + + /// + /// An optional display name for the intent that may be used in UI instead of the name. + /// + public string DisplayName { get; set; } + + /// + /// A comma separated list of the types of contexts the intent offered by the application + /// can process, where the first part of the context type is the namespace e.g."fdc3.contact, + /// org.symphony.contact" + /// + public IEnumerable Contexts { get; set; } + + /// + /// An optional type for output returned by the application, if any, when resolving this intent. + /// May indicate a context type by type name (e.g. "fdc3.instrument"), a channel (e.g. "channel") + /// or a combination that indicates a channel that returns a particular + /// context type (e.g. "channel"). + /// + public string? ResultType { get; set; } + + /// + /// Custom configuration for the intent that may be required for a particular desktop agent. + /// + public object? CustomConfig { get; set; } + } +} diff --git a/src/Fdc3.AppDirectory/Intents.cs b/src/Fdc3.AppDirectory/Intents.cs new file mode 100644 index 0000000..48d2f59 --- /dev/null +++ b/src/Fdc3.AppDirectory/Intents.cs @@ -0,0 +1,43 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. 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. + */ + +using System.Collections.Generic; + +namespace MorganStanley.Fdc3.AppDirectory +{ + /// + /// Describes the app's interactions with intents. + /// + public class Intents + { + /// + /// A mapping of Intents names that an app listens for via fdc3.addIntentListener() to their configuration. + /// Used to support intent resolution by desktop agents.Replaces the intents element used in appD records + /// prior to FDC3 2.0. + /// + public Dictionary? ListensFor { get; set; } + + /// + /// A mapping of Intent names that an app raises (via fdc3.raiseIntent) + /// to an array of context type names that it may be raised with. + /// Use the intent name "any" to represent use of the + /// fdc3.raiseIntentForContext and fdc3.findIntentForContext functions, + /// which allow the user to select from intents available for a specified context type. + /// This metadata is not currently used by the desktop agent, but is provided to + /// help find apps that will interoperate with this app and to document API + /// interactions for use by other app developers. + /// + public Dictionary>? Raises { get; set; } + } +} diff --git a/src/Fdc3.AppDirectory/Interop.cs b/src/Fdc3.AppDirectory/Interop.cs new file mode 100644 index 0000000..c4163b6 --- /dev/null +++ b/src/Fdc3.AppDirectory/Interop.cs @@ -0,0 +1,51 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. 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. + */ + +using System.Collections.Generic; + +namespace MorganStanley.Fdc3.AppDirectory +{ + /// + /// Metadata that describes how the application uses FDC3 APIs. This metadata serves multiple purposes: + /// + /// + /// It supports intent resolution by a desktop agent, by declaring what intents an app listens for. + /// + /// + /// It may be used, for example in an app catalog UI, to find apps that 'interoperate with' other apps. + /// + /// + /// It provides a standard location to document how the app interacts with user channels, app channels, + /// and intents, for use by other app developers and desktop assemblers. + /// + /// + /// + public class Interop + { + /// + /// + /// + public Intents? Intents { get; set; } + + /// + /// + /// + public UserChannels? UserChannels { get; set; } + + /// + /// List of + /// + public IEnumerable? AppChannels { get; set; } + } +} diff --git a/src/Fdc3.AppDirectory/LocalizedVersion.cs b/src/Fdc3.AppDirectory/LocalizedVersion.cs new file mode 100644 index 0000000..bc9f9d3 --- /dev/null +++ b/src/Fdc3.AppDirectory/LocalizedVersion.cs @@ -0,0 +1,22 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. 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. + */ + +namespace MorganStanley.Fdc3.AppDirectory +{ + public class LocalizedVersion + { + public string? Title { get; set; } + public string? Description { get; set; } + } +} diff --git a/src/Fdc3.AppDirectory/MorganStanley.Fdc3.AppDirectory.csproj b/src/Fdc3.AppDirectory/MorganStanley.Fdc3.AppDirectory.csproj new file mode 100644 index 0000000..dca2bd1 --- /dev/null +++ b/src/Fdc3.AppDirectory/MorganStanley.Fdc3.AppDirectory.csproj @@ -0,0 +1,45 @@ + + + + MorganStanley.Fdc3.AppDirectory + MorganStanley.Fdc3.AppDirectory + 2.0.0 + alpha.5 + .NET FDC3 Newtonsoft JSON + true + ..\keypair.snk + README.md + netstandard2.0 + enable + 8.0 + https://github.com/morganstanley/fdc3-dotnet + .NET Standard 2.0 declarations to implement FDC3 AppDirectory. + FDC3 + + + + true + 9999 + + + + True + 9999 + + + + + True + + + + True + \ + + + + + + + + diff --git a/src/Fdc3.AppDirectory/UserChannels.cs b/src/Fdc3.AppDirectory/UserChannels.cs new file mode 100644 index 0000000..632635c --- /dev/null +++ b/src/Fdc3.AppDirectory/UserChannels.cs @@ -0,0 +1,37 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. 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. + */ + +using System.Collections.Generic; + +namespace MorganStanley.Fdc3.AppDirectory +{ + /// + /// Describes the application's use of context types on User Channels. + /// This metadata is not currently used by the desktop agent, but is provided + /// to help find apps that will interoperate with this app and to document API + /// interactions for use by other app developers. + /// + public class UserChannels + { + /// + /// Context type names that are broadcast by the application. + /// + public IEnumerable? Broadcasts { get; set; } + + /// + /// Context type names that the application listens for. + /// + public IEnumerable? ListensFor { get; set; } + } +} diff --git a/src/Fdc3.NewtonsoftJson/MorganStanley.Fdc3.NewtonsoftJson.csproj b/src/Fdc3.NewtonsoftJson/MorganStanley.Fdc3.NewtonsoftJson.csproj index eecec0b..fdb28ed 100644 --- a/src/Fdc3.NewtonsoftJson/MorganStanley.Fdc3.NewtonsoftJson.csproj +++ b/src/Fdc3.NewtonsoftJson/MorganStanley.Fdc3.NewtonsoftJson.csproj @@ -43,6 +43,7 @@ + diff --git a/src/Fdc3.NewtonsoftJson/Serialization/Fdc3AppConverter.cs b/src/Fdc3.NewtonsoftJson/Serialization/Fdc3AppConverter.cs new file mode 100644 index 0000000..9d68f4b --- /dev/null +++ b/src/Fdc3.NewtonsoftJson/Serialization/Fdc3AppConverter.cs @@ -0,0 +1,62 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. 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. + */ + +using MorganStanley.Fdc3.AppDirectory; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; + + +namespace MorganStanley.Fdc3.NewtonsoftJson.Serialization +{ + public class Fdc3AppConverter : JsonConverter + { + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + var jsonObject = JObject.Load(reader); + + if (Enum.TryParse(jsonObject["type"]?.ToString(), true, out AppType appType)) + { + switch (appType) + { + case AppType.Web: + return serializer.Deserialize>(jsonObject.CreateReader()); + case AppType.Citrix: + return serializer.Deserialize>(jsonObject.CreateReader()); + case AppType.Native: + return serializer.Deserialize>(jsonObject.CreateReader()); + case AppType.OnlineNative: + return serializer.Deserialize>(jsonObject.CreateReader()); + case AppType.Other: + return serializer.Deserialize>(jsonObject.CreateReader()); + } + } + + throw new InvalidOperationException("Unknown AppType. Possible values are: web, native, citrix, onlineNative, other"); + } + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + + public override bool CanConvert(Type objectType) + { + return objectType == typeof(Fdc3App); + } + + public override bool CanRead => true; + public override bool CanWrite => false; + } +} diff --git a/src/Fdc3.NewtonsoftJson/Serialization/Fdc3JsonSerializerSettings.cs b/src/Fdc3.NewtonsoftJson/Serialization/Fdc3JsonSerializerSettings.cs index 7c9287a..7814a18 100644 --- a/src/Fdc3.NewtonsoftJson/Serialization/Fdc3JsonSerializerSettings.cs +++ b/src/Fdc3.NewtonsoftJson/Serialization/Fdc3JsonSerializerSettings.cs @@ -30,7 +30,7 @@ public Fdc3JsonSerializerSettings() { NamingStrategy = new Fdc3CamelCaseNamingStrategy() }; - this.Converters = new JsonConverter[] { new StringEnumConverter(new CamelCaseNamingStrategy()), new RecipientJsonConverter() }; + this.Converters = new JsonConverter[] { new StringEnumConverter(new CamelCaseNamingStrategy()), new RecipientJsonConverter(), new Fdc3AppConverter() }; } } } \ No newline at end of file diff --git a/src/Tests/MorganStanley.Fdc3.AppDirectory.Tests/DeserializationTest.cs b/src/Tests/MorganStanley.Fdc3.AppDirectory.Tests/DeserializationTest.cs new file mode 100644 index 0000000..40131d3 --- /dev/null +++ b/src/Tests/MorganStanley.Fdc3.AppDirectory.Tests/DeserializationTest.cs @@ -0,0 +1,82 @@ + +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. 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. + */ + +using MorganStanley.Fdc3.NewtonsoftJson.Serialization; +using Newtonsoft.Json; + +namespace MorganStanley.Fdc3.AppDirectory.Tests +{ + public class DeserializationTest + { + [Fact] + public void AppDAppDeserializationTest() + { + string jsonString = File.ReadAllText("TestJsons\\SampleAppForInterop.json"); + +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + Fdc3App app = JsonConvert.DeserializeObject(jsonString, new Fdc3JsonSerializerSettings()); +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. + + Assert.Equal("my-application", app!.AppId); + Assert.Equal("my-application", app.Name); + Assert.Equal("My Application", app.Title); + Assert.Equal("An example application that uses FDC3 and fully describes itself in an AppD record.", app.Description); + Assert.Equal("1.0.0", app.Version); + Assert.Equal("My example application definition", app.ToolTip); + Assert.Equal("en-US", app.Lang); + Assert.Equal("fdc3@finos.org", app.ContactEmail); + Assert.Equal("fdc3-maintainers@finos.org", app.SupportEmail); + Assert.Equal("http://example.domain.com/", app.MoreInfo); + Assert.Equal("Example App, Inc.", app.Publisher); + Assert.Equal(AppType.Web, app.Type); + Assert.Equal(3, app.Categories!.Count()!); + Assert.Contains("market data", app.Categories!); + Assert.Contains("research", app.Categories!); + Assert.Contains("news", app.Categories!); + Assert.Single(app.Icons!); + Assert.Equal("http://example.domain.com/assets/my-app-icon.png", app.Icons!.First().Src); + Assert.Equal("256x256", app.Icons!.First().Size); + Assert.Equal("image/png", app.Icons!.First().Type); + Assert.Equal(2, app.Screenshots!.Count()); + Assert.Equal("http://example.domain.com/assets/my-app-screenshot-1.png", app.Screenshots!.First().Src); + Assert.Equal("The first screenshot of my example app", app.Screenshots!.First().Label); + Assert.Equal("image/png", app.Screenshots!.First().Type); + Assert.Equal("800x600", app.Screenshots!.First().Size); + Assert.IsType(app.Details); + Assert.Equal("http://example.domain.com/app.html", ((WebAppDetails)app.Details).Url); + Assert.Contains("Finsemble", app.HostManifests!.Keys); + Assert.Contains("Glue42", app.HostManifests.Keys); + Assert.Contains("Web App Manifest", app.HostManifests.Keys); + Assert.Contains("ViewChart", app.Interop!.Intents!.ListensFor!.Keys); + Assert.Contains("myApp.GetPrice", app.Interop.Intents.ListensFor.Keys); + Assert.Contains("fdc3.instrument", app.Interop!.Intents!.ListensFor!["myApp.GetPrice"].Contexts!); + Assert.Equal("Get Price", app.Interop!.Intents!.ListensFor!["myApp.GetPrice"].DisplayName); + Assert.Equal("myApp.quote", app.Interop!.Intents!.ListensFor!["myApp.GetPrice"].ResultType); + Assert.Contains("ViewOrders", app.Interop.Intents.Raises!.Keys); + Assert.Contains("fdc3.instrument", app.Interop.Intents.Raises!["ViewOrders"]); + Assert.Contains("StartEmail", app.Interop.Intents.Raises.Keys); + Assert.Equal(2, app.Interop.UserChannels!.Broadcasts!.Count()!); + Assert.Equal(2, app.Interop.UserChannels!.ListensFor!.Count()!); + Assert.Contains("fdc3.instrument", app.Interop!.UserChannels!.Broadcasts!); + Assert.Contains("fdc3.organization", app.Interop!.UserChannels!.ListensFor!); + Assert.Single(app.Interop.AppChannels!); + Assert.Equal("myApp.quotes,", app.Interop!.AppChannels!.First().Name); + Assert.Contains("myApp.quote", app.Interop.AppChannels!.First().Broadcasts!); + Assert.Contains("fdc3.instrument", app.Interop.AppChannels!.First().ListensFor!); + Assert.Contains("fr-FR", app.LocalizedVersions!.Keys); + + } + } +} \ No newline at end of file diff --git a/src/Tests/MorganStanley.Fdc3.AppDirectory.Tests/MorganStanley.Fdc3.AppDirectory.Tests.csproj b/src/Tests/MorganStanley.Fdc3.AppDirectory.Tests/MorganStanley.Fdc3.AppDirectory.Tests.csproj new file mode 100644 index 0000000..724cacb --- /dev/null +++ b/src/Tests/MorganStanley.Fdc3.AppDirectory.Tests/MorganStanley.Fdc3.AppDirectory.Tests.csproj @@ -0,0 +1,40 @@ + + + + net6.0 + enable + enable + + false + + + + + + + + + PreserveNewest + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + diff --git a/src/Tests/MorganStanley.Fdc3.AppDirectory.Tests/TestJsons/SampleAppForInterop.json b/src/Tests/MorganStanley.Fdc3.AppDirectory.Tests/TestJsons/SampleAppForInterop.json new file mode 100644 index 0000000..0fc814d --- /dev/null +++ b/src/Tests/MorganStanley.Fdc3.AppDirectory.Tests/TestJsons/SampleAppForInterop.json @@ -0,0 +1,112 @@ +{ + "appId": "my-application", + "name": "my-application", + "title": "My Application", + "description": "An example application that uses FDC3 and fully describes itself in an AppD record.", + "categories": [ "market data", "research", "news" ], + "version": "1.0.0", + "tooltip": "My example application definition", + "lang": "en-US", + "icons": [ + { + "src": "http://example.domain.com/assets/my-app-icon.png", + "size": "256x256", + "type": "image/png" + } + ], + "screenshots": [ + { + "src": "http://example.domain.com/assets/my-app-screenshot-1.png", + "label": "The first screenshot of my example app", + "type": "image/png", + "size": "800x600" + }, + { + "src": "http://example.domain.com/assets/my-app-screenshot-2.png", + "label": "The second screenshot of my example app", + "type": "image/png", + "size": "800x600" + } + ], + "contactEmail": "fdc3@finos.org", + "supportEmail": "fdc3-maintainers@finos.org", + "moreInfo": "http://example.domain.com/", + "publisher": "Example App, Inc.", + "type": "web", + "details": { "url": "http://example.domain.com/app.html" }, + "hostManifests": { + "Finsemble": { + "window": { + "left": 120, + "top": 120, + "width": 600, + "height": 800, + "options": { "minWidth": 75 } + }, + "foreign": { + "components": { + "App Launcher": { "launchableByUser": true }, + "Window Manager": { + "FSBLHeader": true, + "persistWindowState": true + } + } + }, + "interop": { "autoConnect": true } + }, + "Glue42": { + "type": "window", + "details": { + "height": 800, + "width": 600, + "left": 120, + "top": 120, + "mode": "tab", + "allowChannels": true, + "loader": { + "enabled": true, + "hideOnLoad": true + } + }, + "customProperties": { "folder": "FDC3 Toolbox" } + }, + "Web App Manifest": "http://example.domain.com/my-app.json" + }, + "interop": { + "intents": { + "listensFor": { + "ViewChart": { + "displayName": "View Chart", + "contexts": [ "fdc3.instrument" ] + }, + "myApp.GetPrice": { + "displayName": "Get Price", + "contexts": [ "fdc3.instrument" ], + "resultType": "myApp.quote" + } + }, + "raises": { + "ViewOrders": [ "fdc3.instrument", "fdc3.organization" ], + "StartEmail": [ "fdc3.email" ] + } + }, + "userChannels": { + "broadcasts": [ "fdc3.instrument", "fdc3.organization" ], + "listensFor": [ "fdc3.instrument", "fdc3.organization" ] + }, + "appChannels": [ + { + "name": "myApp.quotes,", + "description": "Used to share a stream of quotes for currently displayed instrument and may be used to change the currently displayed symbol,", + "broadcasts": [ "myApp.quote" ], + "listensFor": [ "fdc3.instrument" ] + } + ] + }, + "localizedVersions": { + "fr-FR": { + "title": "Mon application,", + "description": "Un exemple d'application qui utilise FDC3 et se décrit entièrement dans un enregistrement AppD." + } + } +} \ No newline at end of file diff --git a/src/Tests/MorganStanley.Fdc3.AppDirectory.Tests/Usings.cs b/src/Tests/MorganStanley.Fdc3.AppDirectory.Tests/Usings.cs new file mode 100644 index 0000000..89c3803 --- /dev/null +++ b/src/Tests/MorganStanley.Fdc3.AppDirectory.Tests/Usings.cs @@ -0,0 +1,14 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. 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. + */ +global using Xunit; \ No newline at end of file diff --git a/src/fdc3-dotnet.sln b/src/fdc3-dotnet.sln index e2060a3..a0733e0 100644 --- a/src/fdc3-dotnet.sln +++ b/src/fdc3-dotnet.sln @@ -42,6 +42,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MorganStanley.Fdc3.Newtonso EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfFdc3", "Examples\WpfFdc3\WpfFdc3.csproj", "{06AD2640-C708-4C01-BF02-82D824CB09C1}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MorganStanley.Fdc3.AppDirectory", "Fdc3.AppDirectory\MorganStanley.Fdc3.AppDirectory.csproj", "{C741FC63-8954-473D-862A-F7F5AFE11E60}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MorganStanley.Fdc3.AppDirectory.Tests", "Tests\MorganStanley.Fdc3.AppDirectory.Tests\MorganStanley.Fdc3.AppDirectory.Tests.csproj", "{88BF9BA6-2934-4904-8952-DB733E4CBD48}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -68,6 +72,14 @@ Global {06AD2640-C708-4C01-BF02-82D824CB09C1}.Debug|Any CPU.Build.0 = Debug|Any CPU {06AD2640-C708-4C01-BF02-82D824CB09C1}.Release|Any CPU.ActiveCfg = Release|Any CPU {06AD2640-C708-4C01-BF02-82D824CB09C1}.Release|Any CPU.Build.0 = Release|Any CPU + {C741FC63-8954-473D-862A-F7F5AFE11E60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C741FC63-8954-473D-862A-F7F5AFE11E60}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C741FC63-8954-473D-862A-F7F5AFE11E60}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C741FC63-8954-473D-862A-F7F5AFE11E60}.Release|Any CPU.Build.0 = Release|Any CPU + {88BF9BA6-2934-4904-8952-DB733E4CBD48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {88BF9BA6-2934-4904-8952-DB733E4CBD48}.Debug|Any CPU.Build.0 = Debug|Any CPU + {88BF9BA6-2934-4904-8952-DB733E4CBD48}.Release|Any CPU.ActiveCfg = Release|Any CPU + {88BF9BA6-2934-4904-8952-DB733E4CBD48}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -77,6 +89,7 @@ Global {D932070B-937D-440F-9D79-B51C8F850E9E} = {97CAC97B-DB3A-4A45-9209-3BAD231B4837} {A4FC0A7A-AD7D-4FDD-8143-46A63A65C96E} = {97CAC97B-DB3A-4A45-9209-3BAD231B4837} {06AD2640-C708-4C01-BF02-82D824CB09C1} = {6C9A6509-FC32-4870-8AD3-9D0AE546A3D9} + {88BF9BA6-2934-4904-8952-DB733E4CBD48} = {97CAC97B-DB3A-4A45-9209-3BAD231B4837} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {356A9BB9-BD56-40C0-B1ED-06F7AF0C4BCA}