예제 #1
0
        /// <summary>
        /// Loads the Resource from the specified <see cref="Stream"/>. You shouldn't need this method in almost all cases.
        /// Only use it when you know exactly what you're doing. Consider requesting the Resource from the <see cref="ContentProvider"/> instead.
        /// </summary>
        /// <typeparam name="T">
        /// Desired Type of the returned reference. Does not affect the loaded Resource in any way - it is simply returned as T.
        /// Results in returning null if the loaded Resource's Type isn't assignable to T.
        /// </typeparam>
        /// <param name="str">The stream to load the Resource from.</param>
        /// <param name="resPath">The path that is assumed as the loaded Resource's origin.</param>
        /// <param name="loadCallback">An optional callback that is invoked right after loading the Resource, but before initializing it.</param>
        /// <param name="initResource">
        /// Specifies whether or not the Resource is initialized by calling <see cref="Resource.OnLoaded"/>. Never attempt to use
        /// uninitialized Resources or register them in the <see cref="ContentProvider"/>.
        /// </param>
        /// <returns>The Resource that has been loaded.</returns>
        public static T Load <T>(Serializer formatter, string resPath = null, Action <T> loadCallback = null, bool initResource = true) where T : Resource
        {
            T newContent = null;

            try
            {
                Resource res = formatter.ReadObject <Resource>();
                if (res == null)
                {
                    throw new Exception("Deserializing Resource failed.");
                }

                res.initState = InitState.Initializing;
                res.path      = resPath;
                if (loadCallback != null)
                {
                    loadCallback(res as T);                       // Callback before initializing.
                }
                if (initResource)
                {
                    Init(res);
                }
                newContent = res as T;
            }
            catch (Exception e)
            {
                Logs.Core.WriteError("Can't load {0} from '{1}', because an error occurred: {3}{2}",
                                     LogFormat.Type(typeof(T)),
                                     resPath ?? formatter.ToString(),
                                     LogFormat.Exception(e),
                                     Environment.NewLine);
            }

            return(newContent);
        }
예제 #2
0
 /// <summary>
 /// Returns a string that can be used for representing a <see cref="System.Reflection.TypeInfo"/> in log entries.
 /// </summary>
 /// <param name="type"></param>
 /// <returns></returns>
 public static string Type(TypeInfo type)
 {
     if (type == null)
     {
         return("null");
     }
     return(LogFormat.Type(type.AsType()));
 }
 public override string ToString()
 {
     if (this.SkipIfExists > 0)
     {
         return(string.Format("Skip {0} if {1} exists",
                              this.SkipIfExists,
                              LogFormat.Type(this.RequiredType)));
     }
     else
     {
         return(string.Format("Require {0} or create {1}",
                              LogFormat.Type(this.RequiredType),
                              LogFormat.Type(this.CreateType)));
     }
 }
        /// <summary>
        /// Adds an already loaded plugin Assembly to the internal Cohee T registry.
        /// You shouldn't need to call this method in general, since Cohee manages its plugins
        /// automatically.
        /// </summary>
        /// <remarks>
        /// This method can be useful in certain cases when it is necessary to treat an Assembly as a
        /// Cohee plugin, even though it isn't located in the Plugins folder, or is not available
        /// as a file at all. A typical case for this is Unit Testing where the testing Assembly may
        /// specify additional Duality types such as Components, Resources, etc.
        /// </remarks>
        /// <param name="pluginAssembly"></param>
        /// <param name="pluginFilePath"></param>
        /// <returns></returns>
        public T LoadPlugin(Assembly pluginAssembly, string pluginFilePath)
        {
            this.disposedPlugins.Remove(pluginAssembly);

            string asmName = pluginAssembly.GetShortAssemblyName();
            T      plugin  = this.pluginRegistry.Values.FirstOrDefault(p => p.AssemblyName == asmName);

            if (plugin != null)
            {
                return(plugin);
            }

            try
            {
                TypeInfo pluginType = pluginAssembly.ExportedTypes
                                      .Select(t => t.GetTypeInfo())
                                      .FirstOrDefault(t => typeof(T).GetTypeInfo().IsAssignableFrom(t));

                if (pluginType == null)
                {
                    throw new Exception(string.Format(
                                            "Plugin does not contain a public {0} class.",
                                            typeof(T).Name));
                }

                plugin = (T)pluginType.CreateInstanceOf();

                if (plugin == null)
                {
                    throw new Exception(string.Format(
                                            "Failed to instantiate {0} class.",
                                            LogFormat.Type(pluginType.GetType())));
                }

                plugin.FilePath = pluginFilePath;
                plugin.FileHash = this.assemblyLoader.GetAssemblyHash(pluginFilePath);

                this.pluginRegistry.Add(plugin.AssemblyName, plugin);
            }
            catch (Exception e)
            {
                this.pluginLog.WriteError("Error loading plugin: {0}", LogFormat.Exception(e));
                this.disposedPlugins.Add(pluginAssembly);
                plugin = null;
            }

            return(plugin);
        }
예제 #5
0
        /// <summary>
        /// Returns a string that can be used for representing an exception in log entries.
        /// It usually does not include the full call stack and is significantly shorter than
        /// an <see cref="System.Exception">Exceptions</see> ToString method.
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        public static string Exception(Exception e, bool callStack = true)
        {
            if (e == null)
            {
                return("null");
            }

            string eName = LogFormat.Type(e.GetType());

            return(string.Format(System.Globalization.CultureInfo.InvariantCulture,
                                 "{0}: {1}{3}CallStack:{3}{2}",
                                 eName,
                                 e.Message,
                                 e.StackTrace,
                                 Environment.NewLine));
        }
            public void EnsureCreationChain(ComponentRequirementMap map)
            {
                if (this.initCreationChain == RecursiveInit.Initialized)
                {
                    return;
                }
                if (this.initCreationChain == RecursiveInit.InProgress)
                {
                    Logs.Core.WriteWarning(
                        "Detected a cyclic Component requirement in {0}. Requirements can not be ensured for cyclic dependencies.",
                        LogFormat.Type(this.Component));
                    return;
                }

                this.initCreationChain = RecursiveInit.InProgress;
                this.InitCreationChain(map);
                this.initCreationChain = RecursiveInit.Initialized;
            }
예제 #7
0
        /// <summary>
        /// Clears the specified constraint graph of all loops.
        /// </summary>
        /// <param name="graph"></param>
        private static void ResolveConstraintLoops(Dictionary <Type, List <OrderConstraint> > graph)
        {
            while (true)
            {
                List <OrderConstraint> loop = FindConstraintLoop(graph);
                if (loop == null)
                {
                    return;
                }

                // Found a loop? Find the weakest link in it
                OrderConstraint weakestLink = loop[0];
                for (int i = 1; i < loop.Count; i++)
                {
                    OrderConstraint link = loop[i];
                    if ((int)link.Priority < (int)weakestLink.Priority)
                    {
                        weakestLink = link;
                    }
                }

                // If the loops weakest link was an explicit constraint, log a warning
                if ((int)weakestLink.Priority >= (int)ConstraintPriority.ExplicitWeak)
                {
                    Logs.Core.WriteWarning(
                        "Found a loop in the component execution order constraint graph. Ignoring the weakest constraint " +
                        "({0} must be executed before {1}). Please check your ExecutionOrder attributes.",
                        LogFormat.Type(weakestLink.FirstType),
                        LogFormat.Type(weakestLink.LastType));
                }

                // Remove the weakest link
                List <OrderConstraint> links = graph[weakestLink.FirstType];
                links.Remove(weakestLink);
                if (links.Count == 0)
                {
                    graph.Remove(weakestLink.FirstType);
                }
            }
        }
예제 #8
0
        private static CreateMethod CreateObjectActivator(TypeInfo typeInfo, out object firstResult)
        {
            Exception lastError = null;
            CreateMethod activator;
            firstResult = null;

            // Filter out non-instantiatable Types
            if (typeInfo.IsAbstract || typeInfo.IsInterface || typeInfo.IsGenericTypeDefinition)
            {
                activator = nullObjectActivator;
            }
            // If the caller wants a string, just return an empty one
            else if (typeInfo.AsType() == typeof(string))
            {
                activator = () => "";
            }
            // If the caller wants an array, create an empty one
            else if (typeInfo.IsArray && typeInfo.GetArrayRank() == 1)
            {
                activator = () => Array.CreateInstance(typeInfo.GetElementType(), 0);
            }
            // For structs, boxing a default(T) is sufficient
            else if (typeInfo.IsValueType)
            {
                var lambda = Expression.Lambda<CreateMethod>(Expression.Convert(Expression.Default(typeInfo.AsType()), typeof(object)));
                activator = lambda.Compile();
            }
            else
            {
                activator = nullObjectActivator;

                // Retrieve constructors, sorted from trivial to parameter-rich
                ConstructorInfo[] constructors = typeInfo.DeclaredConstructors
                    .Where(c => !c.IsStatic)
                    .Select(c => new { Info = c, ParamCount = c.GetParameters().Length })
                    .OrderBy(s => s.ParamCount)
                    .Select(s => s.Info)
                    .ToArray();

                foreach (ConstructorInfo con in constructors)
                {
                    // Prepare constructor argument values - just use default(T) for all of them.
                    ParameterInfo[] conParams = con.GetParameters();
                    Expression[] args = new Expression[conParams.Length];
                    for (int i = 0; i < args.Length; i++)
                    {
                        Type paramType = conParams[i].ParameterType;
                        args[i] = Expression.Default(paramType);
                    }

                    // Compile a lambda method invoking the constructor
                    var lambda = Expression.Lambda<CreateMethod>(Expression.New(con, args));
                    activator = lambda.Compile();

                    // Does it work?
                    firstResult = CheckActivator(activator, out lastError);
                    if (firstResult != null)
                        break;
                }

                // If there were no suitable constructors, log a generic warning.
                if (constructors.Length == 0)
                {
                    Logs.Core.WriteWarning(
                        "Failed to create object of Type {0}. Make sure there is a trivial constructor.",
                        LogFormat.Type(typeInfo));
                }
            }

            // Test whether our activation method really works, replace with dummy if not
            if (firstResult == null)
            {
                // If we didn't yet try to create an object instance or value, do it now.
                if (lastError == null)
                {
                    firstResult = CheckActivator(activator, out lastError);
                }

                // If there was an error / Exception thrown while creating the object, inform someone.
                if (lastError != null)
                {
                    // If it's a problem in a static constructor, get the inner exception to know what's actually wrong.
                    if (lastError is TypeInitializationException)
                    {
                        Logs.Core.WriteError("Failed to initialize Type {0}: {1}",
                            LogFormat.Type(typeInfo),
                            LogFormat.Exception(lastError.InnerException));
                    }
                    // Otherwise, just do a regular error log.
                    else
                    {
                        Logs.Core.WriteError("Failed to create object of Type {0}: {1}",
                            LogFormat.Type(typeInfo),
                            LogFormat.Exception(lastError));
                    }
                }
            }

            // If we still don't have anything, just use a dummy.
            if (firstResult == null)
                activator = nullObjectActivator;

            return activator;
        }
예제 #9
0
        internal static void InitBackend <T>(out T target, Func <Type, IEnumerable <TypeInfo> > typeFinder = null) where T : class, ICoheeBackend
        {
            if (typeFinder == null)
            {
                typeFinder = GetAvailCoheeTypes;
            }

            Logs.Core.Write("Initializing {0}...", LogFormat.Type(typeof(T)));
            Logs.Core.PushIndent();

            // Generate a list of available backends for evaluation
            List <ICoheeBackend> backends = new List <ICoheeBackend>();

            foreach (TypeInfo backendType in typeFinder(typeof(ICoheeBackend)))
            {
                if (backendType.IsInterface)
                {
                    continue;
                }
                if (backendType.IsAbstract)
                {
                    continue;
                }
                if (!backendType.IsClass)
                {
                    continue;
                }
                if (!typeof(T).GetTypeInfo().IsAssignableFrom(backendType))
                {
                    continue;
                }

                ICoheeBackend backend = backendType.CreateInstanceOf() as ICoheeBackend;
                if (backend == null)
                {
                    Logs.Core.WriteWarning("Unable to create an instance of {0}. Skipping it.", backendType.FullName);
                    continue;
                }
                backends.Add(backend);
            }

            // Sort backends from best to worst
            backends.StableSort((a, b) => b.Priority > a.Priority ? 1 : -1);

            // Try to initialize each one and select the first that works
            T selectedBackend = null;

            foreach (T backend in backends)
            {
                if (appData != null &&
                    appData.SkipBackends != null &&
                    appData.SkipBackends.Any(s => string.Equals(s, backend.Id, StringComparison.OrdinalIgnoreCase)))
                {
                    Logs.Core.Write("Backend '{0}' skipped because of AppData settings.", backend.Name);
                    continue;
                }

                bool available = false;
                try
                {
                    available = backend.CheckAvailable();
                    if (!available)
                    {
                        Logs.Core.Write("Backend '{0}' reports to be unavailable. Skipping it.", backend.Name);
                    }
                }
                catch (Exception e)
                {
                    available = false;
                    Logs.Core.WriteWarning("Backend '{0}' failed the availability check with an exception: {1}", backend.Name, LogFormat.Exception(e));
                }
                if (!available)
                {
                    continue;
                }

                Logs.Core.Write("{0}...", backend.Name);
                Logs.Core.PushIndent();
                {
                    try
                    {
                        backend.Init();
                        selectedBackend = backend;
                    }
                    catch (Exception e)
                    {
                        Logs.Core.WriteError("Failed: {0}", LogFormat.Exception(e));
                    }
                }
                Logs.Core.PopIndent();

                if (selectedBackend != null)
                {
                    break;
                }
            }

            // If we found a proper backend and initialized it, add it to the list of active backends
            if (selectedBackend != null)
            {
                target = selectedBackend;

                TypeInfo selectedBackendType = selectedBackend.GetType().GetTypeInfo();
                corePluginManager.LockPlugin(selectedBackendType.Assembly);
            }
            else
            {
                target = null;
            }

            Logs.Core.PopIndent();
        }
예제 #10
0
        /// <summary>
        /// Returns an existing <see cref="ProfileCounter"/> with the specified name.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name">The <see cref="ProfileCounter"/> name to use for this measurement. For nested measurements, use path strings, e.g. "ParentCounter\ChildCounter"</param>
        /// <returns></returns>
        public static T GetCounter <T>(string name) where T : ProfileCounter
        {
            if (name == null)
            {
                return(null);
            }

            ProfileCounter c;

            if (!counterMap.TryGetValue(name, out c))
            {
                return(null);
            }

            T cc = c as T;

            if (cc == null)
            {
                throw new InvalidOperationException(string.Format("The specified performance counter '{0}' is not a {1}.", name, LogFormat.Type(typeof(T))));
            }
            return(cc);
        }