/// <summary> /// Process the specified directory /// </summary> private static IEnumerable <AppletAsset> ProcessDirectory(string source, String path, ConsoleParameters parms) { List <AppletAsset> retVal = new List <AppletAsset>(); foreach (var itm in Directory.GetFiles(source)) { if (Path.GetFileName(itm).StartsWith(".")) { Console.WriteLine("\t Skipping {0}...", itm); continue; } Console.WriteLine("\t Processing {0}...", itm); if (Path.GetFileName(itm).ToLower() == "manifest.xml") { continue; } else { switch (Path.GetExtension(itm)) { case ".html": case ".htm": case ".xhtml": XElement xe = XElement.Load(itm); // Now we have to iterate throuh and add the asset\ AppletAssetHtml htmlAsset = null; if (xe.Elements().OfType <XElement>().Any(o => o.Name == xs_openiz + "widget")) { var widgetEle = xe.Elements().OfType <XElement>().FirstOrDefault(o => o.Name == xs_openiz + "widget"); htmlAsset = new AppletWidget() { Icon = widgetEle.Element(xs_openiz + "icon")?.Value, Type = (AppletWidgetType)Enum.Parse(typeof(AppletWidgetType), widgetEle.Attribute("type")?.Value), Scope = (AppletWidgetScope)Enum.Parse(typeof(AppletWidgetScope), widgetEle.Attribute("scope")?.Value), Description = widgetEle.Elements().Where(o => o.Name == xs_openiz + "description").Select(o => new LocaleString() { Value = o.Value, Language = o.Attribute("lang")?.Value }).ToList(), Name = widgetEle.Attribute("name")?.Value, Controller = widgetEle.Element(xs_openiz + "controller")?.Value, }; } else { htmlAsset = new AppletAssetHtml(); // View state data htmlAsset.ViewState = xe.Elements().OfType <XElement>().Where(o => o.Name == xs_openiz + "state").Select(o => new AppletViewState() { Name = o.Attribute("name")?.Value, Route = o.Elements().OfType <XElement>().FirstOrDefault(r => r.Name == xs_openiz + "url" || r.Name == xs_openiz + "route")?.Value, IsAbstract = Boolean.Parse(o.Attribute("abstract")?.Value ?? "False"), View = o.Elements().OfType <XElement>().Where(v => v.Name == xs_openiz + "view")?.Select(v => new AppletView() { Name = v.Attribute("name")?.Value, Title = v.Elements().OfType <XElement>().Where(t => t.Name == xs_openiz + "title")?.Select(t => new LocaleString() { Language = t.Attribute("lang")?.Value, Value = t?.Value }).ToList(), Controller = v.Element(xs_openiz + "controller")?.Value }).ToList() }).FirstOrDefault(); htmlAsset.Layout = ResolveName(xe.Attribute(xs_openiz + "layout")?.Value); htmlAsset.Static = xe.Attribute(xs_openiz + "static")?.Value == "true"; } htmlAsset.Titles = new List <LocaleString>(xe.Descendants().OfType <XElement>().Where(o => o.Name == xs_openiz + "title").Select(o => new LocaleString() { Language = o.Attribute("lang")?.Value, Value = o.Value })); htmlAsset.Bundle = new List <string>(xe.Descendants().OfType <XElement>().Where(o => o.Name == xs_openiz + "bundle").Select(o => ResolveName(o.Value))); htmlAsset.Script = new List <AssetScriptReference>(xe.Descendants().OfType <XElement>().Where(o => o.Name == xs_openiz + "script").Select(o => new AssetScriptReference() { Reference = ResolveName(o.Value), IsStatic = Boolean.Parse(o.Attribute("static")?.Value ?? "true") })); htmlAsset.Style = new List <string>(xe.Descendants().OfType <XElement>().Where(o => o.Name == xs_openiz + "style").Select(o => ResolveName(o.Value))); var demand = xe.DescendantNodes().OfType <XElement>().Where(o => o.Name == xs_openiz + "demand").Select(o => o.Value).ToList(); var includes = xe.DescendantNodes().OfType <XComment>().Where(o => o?.Value?.Trim().StartsWith("#include virtual=\"") == true).ToList(); foreach (var inc in includes) { String assetName = inc.Value.Trim().Substring(18); // HACK: Should be a REGEX if (assetName.EndsWith("\"")) { assetName = assetName.Substring(0, assetName.Length - 1); } if (assetName == "content") { continue; } var includeAsset = ResolveName(assetName); inc.AddAfterSelf(new XComment(String.Format("#include virtual=\"{0}\"", includeAsset))); inc.Remove(); } var xel = xe.Descendants().OfType <XElement>().Where(o => o.Name.Namespace == xs_openiz).ToList(); if (xel != null) { foreach (var x in xel) { x.Remove(); } } htmlAsset.Html = xe; retVal.Add(new AppletAsset() { Name = ResolveName(itm.Replace(path, "")), MimeType = "text/html", Content = htmlAsset, Policies = demand }); break; case ".css": retVal.Add(new AppletAsset() { Name = ResolveName(itm.Replace(path, "")), MimeType = "text/css", Content = File.ReadAllText(itm) }); break; case ".js": retVal.Add(new AppletAsset() { Name = ResolveName(itm.Replace(path, "")), MimeType = "text/javascript", Content = parms.Optimize && !itm.Contains("rules") ? new Microsoft.Ajax.Utilities.Minifier().MinifyJavaScript(File.ReadAllText(itm), new Microsoft.Ajax.Utilities.CodeSettings() { MinifyCode = false, StripDebugStatements = true, LocalRenaming = Microsoft.Ajax.Utilities.LocalRenaming.KeepAll, PreserveFunctionNames = true }) : File.ReadAllText(itm) }); break; case ".json": retVal.Add(new AppletAsset() { Name = ResolveName(itm.Replace(path, "")), MimeType = "application/json", Content = File.ReadAllText(itm) }); break; default: string mt = null; retVal.Add(new AppletAsset() { Name = ResolveName(itm.Replace(path, "")), MimeType = mime.TryGetValue(Path.GetExtension(itm), out mt) ? mt : "application/octet-stream", Content = File.ReadAllBytes(itm) }); break; } } } // Process sub directories foreach (var dir in Directory.GetDirectories(source)) { if (!Path.GetFileName(dir).StartsWith(".")) { retVal.AddRange(ProcessDirectory(dir, path, parms)); } else { Console.WriteLine("Skipping directory {0}", dir); } } return(retVal); }
/// <summary> /// Render asset content /// </summary> public byte[] RenderAssetContent(AppletAsset asset, string preProcessLocalization = null) { // First, is there an object already byte[] cacheObject = null; string assetPath = String.Format("{0}?lang={1}", asset.ToString(), preProcessLocalization); if (this.CachePages && s_cache.TryGetValue(assetPath, out cacheObject)) { return(cacheObject); } // Resolve content var content = asset.Content; if (content == null && this.Resolver != null) { content = this.Resolver(asset); } if (content is String) // Content is a string { return(Encoding.UTF8.GetBytes(content as String)); } else if (content is byte[]) // Content is a binary asset { return(content as byte[]); } else if (content is XElement) // Content is XML { using (MemoryStream ms = new MemoryStream()) using (XmlWriter xw = XmlWriter.Create(ms)) { (content as XElement).WriteTo(xw); xw.Flush(); ms.Flush(); return(ms.ToArray()); } } else if (content is AppletAssetHtml) // Content is HTML { // Is the content HTML? var sourceAsset = content as AppletAssetHtml; var htmlAsset = new AppletAssetHtml() { Html = new XElement(sourceAsset.Html), Layout = sourceAsset.Layout, Script = new List <String>(sourceAsset.Script), Titles = new List <LocaleString>(sourceAsset.Titles), Style = new List <string>(sourceAsset.Style) }; XElement htmlContent = null; if (htmlAsset.Static) { htmlContent = htmlAsset.Html as XElement; } else { // Type of tag to render basic content switch (htmlAsset.Html.Name.LocalName) { case "html": // The content is a complete HTML page { htmlContent = htmlAsset.Html as XElement; var headerInjection = this.GetInjectionHeaders(asset, htmlContent.DescendantNodes().OfType <XElement>().Any(o => o.Name == xs_xhtml + "ui-view")); // STRIP - OPENIZJS references var xel = htmlContent.Descendants().OfType <XElement>().Where(o => o.Name == xs_xhtml + "script" && o.Attribute("src")?.Value.Contains("openiz") == true).ToArray(); var head = htmlContent.DescendantNodes().OfType <XElement>().FirstOrDefault(o => o.Name == xs_xhtml + "head"); if (head == null) { head = new XElement(xs_xhtml + "head"); htmlContent.Add(head); } head.Add(headerInjection.Where(o => !head.Elements(o.Name).Any(e => (e.Attributes("src") != null && (e.Attributes("src") == o.Attributes("src"))) || (e.Attributes("href") != null && (e.Attributes("href") == o.Attributes("href")))))); // head.Add(headerInjection); break; } case "body": // The content is an HTML Body element, we must inject the HTML header { htmlContent = htmlAsset.Html as XElement; // Inject special headers var headerInjection = this.GetInjectionHeaders(asset, htmlContent.DescendantNodes().OfType <XElement>().Any(o => o.Name == xs_xhtml + "ui-view")); // Render the bundles var bodyElement = htmlAsset.Html as XElement; htmlContent = new XElement(xs_xhtml + "html", new XAttribute("ng-app", asset.Name), new XElement(xs_xhtml + "head", headerInjection), bodyElement); } break; default: { if (String.IsNullOrEmpty(htmlAsset.Layout)) { htmlContent = htmlAsset.Html as XElement; } else { // Get the layout var layoutAsset = this.ResolveAsset(htmlAsset.Layout, asset); if (layoutAsset == null) { throw new FileNotFoundException(String.Format("Layout asset {0} not found", htmlAsset.Layout)); } using (MemoryStream ms = new MemoryStream(this.RenderAssetContent(layoutAsset, preProcessLocalization))) htmlContent = XDocument.Load(ms).FirstNode as XElement; // Find the <!--#include virtual="content" --> tag var contentNode = htmlContent.DescendantNodes().OfType <XComment>().SingleOrDefault(o => o.Value.Trim() == "#include virtual=\"content\""); if (contentNode != null) { contentNode.AddAfterSelf(htmlAsset.Html as XElement); contentNode.Remove(); } // Injection headers var headerInjection = this.GetInjectionHeaders(asset, htmlContent.DescendantNodes().OfType <XElement>().Any(o => o.Name == xs_xhtml + "ui-view")); var headElement = (htmlContent.Element(xs_xhtml + "head") as XElement); headElement?.Add(headerInjection.Where(o => !headElement.Elements(o.Name).Any(e => (e.Attributes("src") != null && (e.Attributes("src") == o.Attributes("src"))) || (e.Attributes("href") != null && (e.Attributes("href") == o.Attributes("href")))))); } } break; } // switch // Process data bindings var dataBindings = htmlContent.DescendantNodes().OfType <XElement>().Where(o => o.Name.LocalName == "select" && o.Attributes().Any(a => a.Name.Namespace == xs_binding)); foreach (var db in dataBindings) { // Get the databinding data XAttribute source = db.Attributes(xs_binding + "source").FirstOrDefault(), filter = db.Attributes(xs_binding + "filter").FirstOrDefault(), key = db.Attributes(xs_binding + "key").FirstOrDefault(), value = db.Attributes(xs_binding + "value").FirstOrDefault(), orderByDescending = db.Attributes(xs_binding + "orderByDescending").FirstOrDefault(), orderBy = db.Attributes(xs_binding + "orderBy").FirstOrDefault(); var locale = preProcessLocalization; int i = 0; var valueSelector = value?.Value; while (i++ < 2) { try { // Fall back to english? if (value != null) { valueSelector = value.Value.Replace("{{ locale }}", locale); } if (source == null || filter == null) { continue; } // First we want to build the filter Type imsiType = typeof(Patient).GetTypeInfo().Assembly.ExportedTypes.FirstOrDefault(o => o.GetTypeInfo().GetCustomAttribute <XmlRootAttribute>()?.ElementName == source.Value); if (imsiType == null) { continue; } var expressionBuilderMethod = typeof(QueryExpressionParser).GetGenericMethod(nameof(QueryExpressionParser.BuildLinqExpression), new Type[] { imsiType }, new Type[] { typeof(NameValueCollection) }); var filterList = NameValueCollection.ParseQueryString(filter.Value); var expr = expressionBuilderMethod.Invoke(null, new object[] { filterList }); var filterMethod = typeof(IEntitySourceProvider).GetGenericMethod("Query", new Type[] { imsiType }, new Type[] { expr.GetType() }); var dataSource = (filterMethod.Invoke(EntitySource.Current.Provider, new object[] { expr })); // Sort expression if (orderBy != null || orderByDescending != null) { var orderProperty = imsiType.GetRuntimeProperties().FirstOrDefault(o => o.GetCustomAttribute <JsonPropertyAttribute>()?.PropertyName == (orderBy ?? orderByDescending).Value); ParameterExpression orderExpr = Expression.Parameter(dataSource.GetType()); var orderBody = orderExpr.Sort(orderProperty.Name, orderBy == null ? SortOrderType.OrderByDescending : SortOrderType.OrderBy); dataSource = Expression.Lambda(orderBody, orderExpr).Compile().DynamicInvoke(dataSource); } // Render expression Delegate keyExpression = null, valueExpression = null, dataExpression = null; ParameterExpression parameter = Expression.Parameter(imsiType); if (key == null) { keyExpression = Expression.Lambda(Expression.MakeMemberAccess(parameter, imsiType.GetRuntimeProperty(nameof(IIdentifiedEntity.Key))), parameter).Compile(); } else { var rawExpr = new BindingExpressionVisitor().RewriteLambda(expressionBuilderMethod.Invoke(null, new object[] { NameValueCollection.ParseQueryString(key.Value + "=RemoveMe") }) as LambdaExpression); keyExpression = Expression.Lambda(new BindingExpressionVisitor().Visit(rawExpr.Body), rawExpr.Parameters).Compile(); } if (value == null) { valueExpression = Expression.Lambda(Expression.Call(parameter, imsiType.GetRuntimeMethod("ToString", new Type[] { })), parameter).Compile(); } else { var rawExpr = new BindingExpressionVisitor().RewriteLambda(expressionBuilderMethod.Invoke(null, new object[] { NameValueCollection.ParseQueryString(valueSelector + "=RemoveMe") }) as LambdaExpression); valueExpression = Expression.Lambda(rawExpr.Body, rawExpr.Parameters).Compile(); } // Creation of the options foreach (var itm in dataSource as IEnumerable) { var optAtt = new XElement(xs_xhtml + "option"); var keyValue = keyExpression.DynamicInvoke(itm); var valueValue = valueExpression.DynamicInvoke(itm)?.ToString(); if (String.IsNullOrEmpty(valueValue)) { continue; } optAtt.Add(new XAttribute("value", keyValue), new XText(valueValue)); foreach (var dataBinding in db.Attributes().Where(c => c.Name.ToString().StartsWith((xs_binding + "data-").ToString()))) { if (dataBinding != null) { dataExpression = Expression.Lambda(Expression.MakeMemberAccess(parameter, imsiType.GetRuntimeProperty(dataBinding.Value)), parameter).Compile(); var dataValue = dataExpression?.DynamicInvoke(itm)?.ToString(); if (string.IsNullOrEmpty(dataValue)) { continue; } optAtt.Add(new XAttribute(dataBinding.Name.LocalName, dataValue)); } } db.Add(optAtt); } break; } catch { if (locale == "en") { throw; // We can't fallback } locale = "en"; // fallback to english } } } // Now process SSI directives - <!--#include virtual="XXXXXXX" --> var includes = htmlContent.DescendantNodes().OfType <XComment>().Where(o => o?.Value?.Trim().StartsWith("#include virtual=\"") == true).ToList(); foreach (var inc in includes) { String assetName = inc.Value.Trim().Substring(18); // HACK: Should be a REGEX if (assetName.EndsWith("\"")) { assetName = assetName.Substring(0, assetName.Length - 1); } if (assetName == "content") { continue; } var includeAsset = this.ResolveAsset(assetName, asset); if (includeAsset == null) { inc.AddAfterSelf(new XElement(xs_xhtml + "strong", new XText(String.Format("{0} NOT FOUND", assetName)))); inc.Remove(); } else { using (MemoryStream ms = new MemoryStream(this.RenderAssetContent(includeAsset, preProcessLocalization))) { try { var xel = XDocument.Load(ms).Elements().First() as XElement; if (xel.Name == xs_xhtml + "html") { inc.AddAfterSelf(xel.Element(xs_xhtml + "body").Elements()); } else { //var headerInjection = this.GetInjectionHeaders(includeAsset); //var headElement = htmlContent.Element(xs_xhtml + "head"); //headElement?.Add(headerInjection.Where(o => !headElement.Elements(o.Name).Any(e => (e.Attributes("src") != null && (e.Attributes("src") == o.Attributes("src"))) || (e.Attributes("href") != null && (e.Attributes("href") == o.Attributes("href")))))); inc.AddAfterSelf(xel); } inc.Remove(); } catch (Exception e) { throw new XmlException($"Error in Asset: {includeAsset}", e); } } } } // Re-write foreach (var itm in htmlContent.DescendantNodes().OfType <XElement>().SelectMany(o => o.Attributes()).Where(o => o.Value.StartsWith("~"))) { itm.Value = String.Format("/{0}/{1}", asset.Manifest.Info.Id, itm.Value.Substring(2)); //itm.Value = itm.Value.Replace(APPLET_SCHEME, this.AppletBase).Replace(ASSET_SCHEME, this.AssetBase).Replace(DRAWABLE_SCHEME, this.DrawableBase); } // Render Title var headTitle = htmlContent.DescendantNodes().OfType <XElement>().FirstOrDefault(o => o.Name == xs_xhtml + "head"); var title = htmlAsset.GetTitle(preProcessLocalization); if (headTitle != null && !String.IsNullOrEmpty(title)) { headTitle.Add(new XElement(xs_xhtml + "title", new XText(title))); } } // Render out the content using (StringWriter sw = new StringWriter()) using (XmlWriter xw = XmlWriter.Create(sw, new XmlWriterSettings() { OmitXmlDeclaration = true })) { htmlContent.WriteTo(xw); xw.Flush(); String retVal = sw.ToString(); if (!String.IsNullOrEmpty(preProcessLocalization)) { var assetString = this.GetStrings(preProcessLocalization); retVal = this.m_localizationRegex.Replace(retVal, (m) => assetString.FirstOrDefault(o => o.Key == m.Groups[1].Value).Value ?? m.Groups[1].Value); } var byteData = Encoding.UTF8.GetBytes(retVal); // Add to cache lock (s_syncLock) if (!s_cache.ContainsKey(assetPath)) { s_cache.Add(assetPath, byteData); } return(byteData); } } else { return(null); } }
/// <summary> /// Process the specified file /// </summary> public AppletAsset Process(string file, bool optimize) { try { XElement xe = XElement.Load(file); if (xe.Name.Namespace != PakManTool.XS_HTML) { Emit.Message("WARN", "File {0} is not in {1}. Setting namespace", file, PakManTool.XS_HTML); xe.Name = (XNamespace)PakManTool.XS_HTML + xe.Name.LocalName; } // Optimizing? if (optimize) { xe.DescendantNodesAndSelf().OfType <XComment>().Where(o => !o.Value.Contains("#include")).Remove(); } // Now we have to iterate throuh and add the asset\ AppletAssetHtml htmlAsset = null; if (xe.Elements().OfType <XElement>().Any(o => o.Name == (XNamespace)PakManTool.XS_APPLET + "widget")) { var widgetEle = xe.Elements().OfType <XElement>().FirstOrDefault(o => o.Name == (XNamespace)PakManTool.XS_APPLET + "widget"); htmlAsset = new AppletWidget() { Icon = widgetEle.Element((XNamespace)PakManTool.XS_APPLET + "icon")?.Value, Type = (AppletWidgetType)Enum.Parse(typeof(AppletWidgetType), widgetEle.Attribute("type")?.Value), Size = (AppletWidgetSize)Enum.Parse(typeof(AppletWidgetSize), widgetEle.Attribute("size")?.Value ?? "Medium"), View = (AppletWidgetView)Enum.Parse(typeof(AppletWidgetView), widgetEle.Attribute("altViews")?.Value ?? "None"), ColorClass = widgetEle.Attribute("headerClass")?.Value ?? "bg-light", Priority = Int32.Parse(widgetEle.Attribute("priority")?.Value ?? "0"), MaxStack = Int32.Parse(widgetEle.Attribute("maxStack")?.Value ?? "2"), Order = Int32.Parse(widgetEle.Attribute("order")?.Value ?? "0"), Context = widgetEle.Attribute("context")?.Value, Description = widgetEle.Elements().Where(o => o.Name == (XNamespace)PakManTool.XS_APPLET + "description").Select(o => new LocaleString() { Value = o.Value, Language = o.Attribute("lang")?.Value }).ToList(), Name = widgetEle.Attribute("name")?.Value, Controller = widgetEle.Element((XNamespace)PakManTool.XS_APPLET + "controller")?.Value, Guard = widgetEle.Elements().Where(o => o.Name == (XNamespace)PakManTool.XS_APPLET + "guard").Select(o => o.Value).ToList() }; } else { htmlAsset = new AppletAssetHtml(); // View state data htmlAsset.ViewState = xe.Elements().OfType <XElement>().Where(o => o.Name == (XNamespace)PakManTool.XS_APPLET + "state").Select(o => new AppletViewState() { Priority = Int32.Parse(o.Attribute("priority")?.Value ?? "0"), Name = o.Attribute("name")?.Value, Route = o.Elements().OfType <XElement>().FirstOrDefault(r => r.Name == (XNamespace)PakManTool.XS_APPLET + "url" || r.Name == (XNamespace)PakManTool.XS_APPLET + "route")?.Value, IsAbstract = Boolean.Parse(o.Attribute("abstract")?.Value ?? "False"), View = o.Elements().OfType <XElement>().Where(v => v.Name == (XNamespace)PakManTool.XS_APPLET + "view")?.Select(v => new AppletView() { Priority = Int32.Parse(o.Attribute("priority")?.Value ?? "0"), Name = v.Attribute("name")?.Value, Controller = v.Element((XNamespace)PakManTool.XS_APPLET + "controller")?.Value }).ToList() }).FirstOrDefault(); htmlAsset.Titles = xe.Elements().OfType <XElement>().Where(t => t.Name == (XNamespace)PakManTool.XS_APPLET + "title")?.Select(t => new LocaleString() { Language = t.Attribute("lang")?.Value, Value = t?.Value }).ToList(); htmlAsset.Layout = PakManTool.TranslatePath(xe.Attribute((XNamespace)PakManTool.XS_APPLET + "layout")?.Value); htmlAsset.Static = xe.Attribute((XNamespace)PakManTool.XS_APPLET + "static")?.Value == "true"; } htmlAsset.Titles = new List <LocaleString>(xe.Descendants().OfType <XElement>().Where(o => o.Name == (XNamespace)PakManTool.XS_APPLET + "title").Select(o => new LocaleString() { Language = o.Attribute("lang")?.Value, Value = o.Value })); htmlAsset.Bundle = new List <string>(xe.Descendants().OfType <XElement>().Where(o => o.Name == (XNamespace)PakManTool.XS_APPLET + "bundle").Select(o => PakManTool.TranslatePath(o.Value))); htmlAsset.Script = new List <AssetScriptReference>(xe.Descendants().OfType <XElement>().Where(o => o.Name == (XNamespace)PakManTool.XS_APPLET + "script").Select(o => new AssetScriptReference() { Reference = PakManTool.TranslatePath(o.Value), IsStatic = Boolean.Parse(o.Attribute("static")?.Value ?? "true") })); htmlAsset.Style = new List <string>(xe.Descendants().OfType <XElement>().Where(o => o.Name == (XNamespace)PakManTool.XS_APPLET + "style").Select(o => PakManTool.TranslatePath(o.Value))); var demand = xe.DescendantNodes().OfType <XElement>().Where(o => o.Name == (XNamespace)PakManTool.XS_APPLET + "demand").Select(o => o.Value).ToList(); var includes = xe.DescendantNodes().OfType <XComment>().Where(o => o?.Value?.Trim().StartsWith("#include virtual=\"") == true).ToList(); foreach (var inc in includes) { String assetName = inc.Value.Trim().Substring(18); // HACK: Should be a REGEX if (assetName.EndsWith("\"")) { assetName = assetName.Substring(0, assetName.Length - 1); } if (assetName == "content") { continue; } var includeAsset = PakManTool.TranslatePath(assetName); inc.AddAfterSelf(new XComment(String.Format("#include virtual=\"{0}\"", includeAsset))); inc.Remove(); } var xel = xe.Descendants().OfType <XElement>().Where(o => o.Name.Namespace == (XNamespace)PakManTool.XS_APPLET).ToList(); if (xel != null) { foreach (var x in xel) { x.Remove(); } } htmlAsset.Html = xe; return(new AppletAsset() { MimeType = "text/html", Content = htmlAsset, Policies = demand }); } catch (XmlException e) { Emit.Message("ERROR", " {0} is not well formed - {1} - @{2}:{3}", file, e.Message, e.LineNumber, e.LinePosition); throw; } catch (Exception e) { Emit.Message("ERROR", "Cannot process {0} : {1}", file, e.Message); throw; } }
/// <summary> /// Render asset content /// </summary> public byte[] RenderAssetContent(AppletAsset asset, string preProcessLocalization = null, bool staticScriptRefs = true, bool allowCache = true, IDictionary <String, String> bindingParameters = null) { // TODO: This method needs to be cleaned up since it exists from the old/early OpenIZ days // First, is there an object already byte[] cacheObject = null; string assetPath = String.Format("{0}?lang={1}", asset.ToString(), preProcessLocalization); var cacheKey = $"{assetPath};{String.Join(";", bindingParameters?.Select(o => $"{o.Key}={o.Value}") ?? new string[0] { })}"; if (allowCache && this.CachePages && s_cache.TryGetValue(cacheKey, out cacheObject)) { return(cacheObject); } // Resolve content var content = asset.Content; if (content == null && this.Resolver != null) { content = this.Resolver(asset); } if (content is String) // Content is a string { // Inject CSP if (asset.MimeType == "text/javascript" || asset.MimeType == "application/json") { var retVal = content as String; if (bindingParameters != null) { retVal = this.m_bindingRegex.Replace(retVal, (m) => bindingParameters.TryGetValue(m.Groups[1].Value, out string v) ? v : m.ToString()); } cacheObject = Encoding.UTF8.GetBytes(retVal); if (allowCache) { s_cache.TryAdd(cacheKey, cacheObject); } return(cacheObject); } else { return(Encoding.UTF8.GetBytes(content as String)); } } else if (content is byte[]) // Content is a binary asset { // is the content compressed? if (Encoding.UTF8.GetString(content as byte[], 0, 4) == "LZIP") { using (var ms = new MemoryStream(content as byte[])) using (var ls = new SharpCompress.Compressors.LZMA.LZipStream(new NonDisposingStream(ms), SharpCompress.Compressors.CompressionMode.Decompress)) using (var oms = new MemoryStream()) { byte[] buffer = new byte[2048]; int br = 1; while (br > 0) { br = ls.Read(buffer, 0, 2048); oms.Write(buffer, 0, br); } content = oms.ToArray(); if (allowCache) { s_cache.TryAdd(cacheKey, content as byte[]); } return(content as byte[]); } } else { return(content as byte[]); } } else if (content is XElement) // Content is XML { using (MemoryStream ms = new MemoryStream()) using (XmlWriter xw = XmlWriter.Create(ms)) { (content as XElement).WriteTo(xw); xw.Flush(); ms.Flush(); return(ms.ToArray()); } } else if (content is AppletAssetHtml) // Content is HTML { // Is the content HTML? var sourceAsset = content as AppletAssetHtml; var htmlAsset = new AppletAssetHtml() { Html = new XElement(sourceAsset.Html), Layout = sourceAsset.Layout, Script = new List <AssetScriptReference>(sourceAsset.Script), Titles = new List <LocaleString>(sourceAsset.Titles), Style = new List <string>(sourceAsset.Style) }; XElement htmlContent = null; if (htmlAsset.Static) { htmlContent = htmlAsset.Html as XElement; } else { // Type of tag to render basic content switch (htmlAsset.Html.Name.LocalName) { case "html": // The content is a complete HTML page { htmlContent = htmlAsset.Html as XElement; var headerInjection = this.GetInjectionHeaders(asset, htmlContent.DescendantNodes().OfType <XElement>().Any(o => o.Name == xs_xhtml + "ui-view")); // STRIP - SanteDBJS references var xel = htmlContent.Descendants().OfType <XElement>().Where(o => o.Name == xs_xhtml + "script" && o.Attribute("src")?.Value.Contains("SanteDB") == true).ToArray(); var head = htmlContent.DescendantNodes().OfType <XElement>().FirstOrDefault(o => o.Name == xs_xhtml + "head"); if (head == null) { head = new XElement(xs_xhtml + "head"); htmlContent.Add(head); } head.Add(headerInjection.Where(o => !head.Elements(o.Name).Any(e => (e.Attributes("src") != null && (e.Attributes("src") == o.Attributes("src"))) || (e.Attributes("href") != null && (e.Attributes("href") == o.Attributes("href")))))); // Inject any business rules as static refs var body = htmlContent.DescendantNodes().OfType <XElement>().FirstOrDefault(o => o.Name == xs_xhtml + "body"); if (body != null) { body.Add( this.SelectMany(o => o.Assets.Where(a => a.Name.StartsWith("rules/"))).Select(o => new XElement(xs_xhtml + "script", new XAttribute("src", $"/{o.Manifest.Info.Id}/{o.Name}"), new XAttribute("type", "text/javascript"), new XAttribute("nonce", bindingParameters.TryGetValue("csp_nonce", out string nonce) ? nonce : ""), new XText("// Script reference"))) ); } // head.Add(headerInjection); break; } case "body": // The content is an HTML Body element, we must inject the HTML header { htmlContent = htmlAsset.Html as XElement; // Inject special headers var headerInjection = this.GetInjectionHeaders(asset, htmlContent.DescendantNodes().OfType <XElement>().Any(o => o.Name == xs_xhtml + "ui-view")); // Render the bundles var bodyElement = htmlAsset.Html as XElement; htmlContent = new XElement(xs_xhtml + "html", new XAttribute("ng-app", asset.Name), new XElement(xs_xhtml + "head", headerInjection), bodyElement); } break; default: { if (String.IsNullOrEmpty(htmlAsset.Layout)) { htmlContent = htmlAsset.Html as XElement; } else { // Get the layout var layoutAsset = this.ResolveAsset(htmlAsset.Layout, relativeAsset: asset); if (layoutAsset == null) { throw new FileNotFoundException(String.Format("Layout asset {0} not found", htmlAsset.Layout)); } using (MemoryStream ms = new MemoryStream(this.RenderAssetContent(layoutAsset, preProcessLocalization, bindingParameters: bindingParameters))) htmlContent = XDocument.Load(ms).FirstNode as XElement; // Find the <!--#include virtual="content" --> tag var contentNode = htmlContent.DescendantNodes().OfType <XComment>().SingleOrDefault(o => o.Value.Trim() == "#include virtual=\"content\""); if (contentNode != null) { contentNode.AddAfterSelf(htmlAsset.Html as XElement); contentNode.Remove(); } // Injection headers var headerInjection = this.GetInjectionHeaders(asset, htmlContent.DescendantNodes().OfType <XElement>().Any(o => o.Name == xs_xhtml + "ui-view")); var headElement = (htmlContent.Element(xs_xhtml + "head") as XElement); headElement?.Add(headerInjection.Where(o => !headElement.Elements(o.Name).Any(e => (e.Attributes("src") != null && (e.Attributes("src") == o.Attributes("src"))) || (e.Attributes("href") != null && (e.Attributes("href") == o.Attributes("href")))))); } } break; } // switch // Now process SSI directives - <!--#include virtual="XXXXXXX" --> var includes = htmlContent.DescendantNodes().OfType <XComment>().Where(o => o?.Value?.Trim().StartsWith("#include virtual=\"") == true).ToList(); foreach (var inc in includes) { String assetName = inc.Value.Trim().Substring(18); // HACK: Should be a REGEX if (assetName.EndsWith("\"")) { assetName = assetName.Substring(0, assetName.Length - 1); } if (assetName == "content") { continue; } var includeAsset = this.ResolveAsset(assetName, relativeAsset: asset); if (includeAsset == null) { inc.AddAfterSelf(new XElement(xs_xhtml + "strong", new XText(String.Format("{0} NOT FOUND", assetName)))); inc.Remove(); } else { using (MemoryStream ms = new MemoryStream(this.RenderAssetContent(includeAsset, preProcessLocalization, bindingParameters: bindingParameters))) { try { var xel = XDocument.Load(ms).Elements().First() as XElement; if (xel.Name == xs_xhtml + "html") { inc.AddAfterSelf(xel.Element(xs_xhtml + "body").Elements()); } else { //var headerInjection = this.GetInjectionHeaders(includeAsset); //var headElement = htmlContent.Element(xs_xhtml + "head"); //headElement?.Add(headerInjection.Where(o => !headElement.Elements(o.Name).Any(e => (e.Attributes("src") != null && (e.Attributes("src") == o.Attributes("src"))) || (e.Attributes("href") != null && (e.Attributes("href") == o.Attributes("href")))))); inc.AddAfterSelf(xel); } inc.Remove(); } catch (Exception e) { throw new XmlException($"Error in Asset: {includeAsset}", e); } } } } // Re-write foreach (var itm in htmlContent.DescendantNodes().OfType <XElement>().SelectMany(o => o.Attributes()).Where(o => o.Value.StartsWith("~"))) { itm.Value = String.Format("/{0}/{1}", asset.Manifest.Info.Id, itm.Value.Substring(2)); //itm.Value = itm.Value.Replace(APPLET_SCHEME, this.AppletBase).Replace(ASSET_SCHEME, this.AssetBase).Replace(DRAWABLE_SCHEME, this.DrawableBase); } // Render Title var headTitle = htmlContent.DescendantNodes().OfType <XElement>().FirstOrDefault(o => o.Name == xs_xhtml + "head"); var title = htmlAsset.GetTitle(preProcessLocalization); if (headTitle != null && !String.IsNullOrEmpty(title)) { headTitle.Add(new XElement(xs_xhtml + "title", new XText(title))); } } // Render out the content using (StringWriter sw = new StringWriter()) using (XmlWriter xw = XmlWriter.Create(sw, new XmlWriterSettings() { OmitXmlDeclaration = true })) { htmlContent.WriteTo(xw); xw.Flush(); String retVal = sw.ToString(); if (!String.IsNullOrEmpty(preProcessLocalization)) { var assetString = ApplicationServiceContext.Current.GetService <ILocalizationService>().GetStrings(preProcessLocalization); retVal = this.m_localizationRegex.Replace(retVal, (m) => assetString.FirstOrDefault(o => o.Key == m.Groups[1].Value).Value ?? m.Groups[1].Value); } // Binding objects if (bindingParameters != null) { retVal = this.m_bindingRegex.Replace(retVal, (m) => bindingParameters.TryGetValue(m.Groups[1].Value, out string v) ? v : m.ToString()); } var byteData = Encoding.UTF8.GetBytes(retVal); // Add to cache if (allowCache) { s_cache.TryAdd(cacheKey, byteData); } return(byteData); } } else if (content is AppletAssetVirtual virtualContent) // Virtual asset { if (!s_cache.TryGetValue(assetPath, out byte[] data))
/// <summary> /// Get applet asset /// </summary> public object ResolveAppletAsset(AppletAsset navigateAsset) { String itmPath = System.IO.Path.Combine( this.m_appletBaseDir[navigateAsset.Manifest], navigateAsset.Name); if (navigateAsset.MimeType == "text/html") { XElement xe = XElement.Load(itmPath); // Now we have to iterate throuh and add the asset\ AppletAssetHtml htmlAsset = null; if (xe.Elements().OfType <XElement>().Any(o => o.Name == xs_openiz + "widget")) { var widgetEle = xe.Elements().OfType <XElement>().FirstOrDefault(o => o.Name == xs_openiz + "widget"); htmlAsset = new AppletWidget() { Icon = widgetEle.Element(xs_openiz + "icon")?.Value, Type = (AppletWidgetType)Enum.Parse(typeof(AppletWidgetType), widgetEle.Attribute("type")?.Value), Scope = (AppletWidgetScope)Enum.Parse(typeof(AppletWidgetScope), widgetEle.Attribute("scope")?.Value), Description = widgetEle.Elements().Where(o => o.Name == xs_openiz + "description").Select(o => new LocaleString() { Value = o.Value, Language = o.Attribute("lang")?.Value }).ToList(), Name = widgetEle.Attribute("name")?.Value, Controller = widgetEle.Element(xs_openiz + "controller")?.Value, }; } else { htmlAsset = new AppletAssetHtml(); // View state data htmlAsset.ViewState = xe.Elements().OfType <XElement>().Where(o => o.Name == xs_openiz + "state").Select(o => new AppletViewState() { Name = o.Attribute("name")?.Value, Route = o.Elements().OfType <XElement>().FirstOrDefault(r => r.Name == xs_openiz + "url" || r.Name == xs_openiz + "route")?.Value, IsAbstract = Boolean.Parse(o.Attribute("abstract")?.Value ?? "False"), View = o.Elements().OfType <XElement>().Where(v => v.Name == xs_openiz + "view")?.Select(v => new AppletView() { Name = v.Attribute("name")?.Value, Title = v.Elements().OfType <XElement>().Where(t => t.Name == xs_openiz + "title")?.Select(t => new LocaleString() { Language = t.Attribute("lang")?.Value, Value = t?.Value }).ToList(), Controller = v.Element(xs_openiz + "controller")?.Value }).ToList() }).FirstOrDefault(); htmlAsset.Layout = ResolveName(xe.Attribute(xs_openiz + "layout")?.Value); htmlAsset.Static = xe.Attribute(xs_openiz + "static")?.Value == "true"; } htmlAsset.Titles = new List <LocaleString>(xe.Descendants().OfType <XElement>().Where(o => o.Name == xs_openiz + "title").Select(o => new LocaleString() { Language = o.Attribute("lang")?.Value, Value = o.Value })); htmlAsset.Bundle = new List <string>(xe.Descendants().OfType <XElement>().Where(o => o.Name == xs_openiz + "bundle").Select(o => ResolveName(o.Value))); htmlAsset.Script = new List <AssetScriptReference>(xe.Descendants().OfType <XElement>().Where(o => o.Name == xs_openiz + "script").Select(o => new AssetScriptReference() { Reference = ResolveName(o.Value), IsStatic = Boolean.Parse(o.Attribute("static")?.Value ?? "true") })); htmlAsset.Style = new List <string>(xe.Descendants().OfType <XElement>().Where(o => o.Name == xs_openiz + "style").Select(o => ResolveName(o.Value))); var demand = xe.DescendantNodes().OfType <XElement>().Where(o => o.Name == xs_openiz + "demand").Select(o => o.Value).ToList(); var includes = xe.DescendantNodes().OfType <XComment>().Where(o => o?.Value?.Trim().StartsWith("#include virtual=\"") == true).ToList(); foreach (var inc in includes) { String assetName = inc.Value.Trim().Substring(18); // HACK: Should be a REGEX if (assetName.EndsWith("\"")) { assetName = assetName.Substring(0, assetName.Length - 1); } if (assetName == "content") { continue; } var includeAsset = ResolveName(assetName); inc.AddAfterSelf(new XComment(String.Format("#include virtual=\"{0}\"", includeAsset))); inc.Remove(); } var xel = xe.Descendants().OfType <XElement>().Where(o => o.Name.Namespace == xs_openiz).ToList(); if (xel != null) { foreach (var x in xel) { x.Remove(); } } htmlAsset.Html = xe; return(htmlAsset); } else if (navigateAsset.MimeType == "text/javascript" || navigateAsset.MimeType == "text/css" || navigateAsset.MimeType == "application/json" || navigateAsset.MimeType == "text/xml") { var script = File.ReadAllText(itmPath); if (itmPath.Contains("openiz.js") || itmPath.Contains("openiz.min.js")) { script += this.GetShimMethods(); } return(script); } else { return(File.ReadAllBytes(itmPath)); } }