Include multiple CloudFormation templates in CDK - aws-cdk

I have two separate Cloudformation templates, A and B, where B depends on the output of A (e.g., B uses the instance role from A, A creates the instance role).
How do I achieve this in CDK?
const tmpl = new cfninc.CfnInclude(this, `included-template`, {
templateFile: path.join('cfn-templates', 'HI.yaml'),
});
And use the output from tmpl.Outputs['InstanceRoleId']?

You can use resources directly, no need to even create outputs:
const tmpl = tmpl.getResource('InstanceRole') as iam.CfnRole;

Related

With MvcSiteMapProvider Is it possible to programmatically register lots of pages between index ranges?

I'm looking at MVCSiteMapProvider but I can't find anything in documentation that would allow me to register lots of urls by index. I have the following
http://example.com/story/1
...
...
http://example.com/story/7000000
I'd like to be able to use the library to automatically serve these in lots of different files. I've read through all the documentation but can't find anything. It seems really fully featured though so I thought I would ask before rolling my own solution.
You can use a dynamic node provider or implement ISiteMapNodeProvider to programatically supply your own data (including custom ids) from any source.
Dynamic node providers can be added without using an external dependency injection container, but you need to add a "template" node either in XML or using .NET attributes to attach the provider to (see the above link).
public class StoryDynamicNodeProvider : DynamicNodeProviderBase
{
public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node)
{
// Entities would be your entity framework context class
// or repository.
using (var entities = new Entities())
{
// Create a node for each blog post
foreach (var story in entities.Stories)
{
DynamicNode dynamicNode = new DynamicNode();
dynamicNode.Title = story.Title;
// The key of the node that this node will be the child of.
// This works best if you explicitly set the key property/attribute
// of the parent node.
dynamicNode.ParentKey = "Home";
dynamicNode.Key = "Story_" + story.Id;
dynamicNode.Controller = "Story";
dynamicNode.Action = "Details";
// Add the "id" (or any other custom route values)
dynamicNode.RouteValues.Add("id", story.Id);
yield return dynamicNode;
}
}
}
}
Using ISiteMapNodeProvider you can build the entire SiteMap structure including the root node, but currently it requires using an external DI container to inject a custom implementation.
There is an example here of how you could implement ISiteMapNodeProvider yourself. Here is an example of injecting a custom implementation using SimpleInjector.
Do note that there is currently a limitation in the 10s of thousands for the total number of nodes on a server because they are cached in memory, so if you have that many nodes using preservedRouteParameters is a better choice. However, it has a limitation that the individual URLs can only appear in the SiteMapPath, but not in the Menu, SiteMap, or XML Sitemap for search engines.
I think this will be the answer you are looking for:
Add the below to the node in your sitemap.
preservedRouteParameters="id"
There is more documentation here, How to Config MVCSiteMap to realize the parameters?

How to print a list of objects in a Velocity template?

This is a pretty basic problem and I'm pretty sure I'm doing something wrong or making some assumption. Here goes.
I'm writing a Jira plugin, which uses the Velocity template system. I have a list of ResultRow objects where ResultRow is a class with a single member variable: String key:
public class ResultRow {
public String key;
}
I have a list of these ResultRows:
List<ResultRow> rows = new ArrayList<ResultRow>();
ResultRow row = new ResultRow();
row.key = "foo";
rows.add(foo);
Map<String, Object> velocityParams = new HashMap<String, Object>();
velocityParams.put("rows", rows);
return descriptor.getHtml("view", velocityParams);
and I am trying to list these rows in a template with the following:
#foreach ($row in $rows)
<tr><td>$row.key</td></tr>
#end
I want the output to be: foo. Maddeningly, the template system simply prints the literal string "$row.key" instead of the contents of key. To verify that "$row" is indeed an object, I used the template:
#foreach ($row in $rows)
<tr><td>$row</td></tr>
#end
and the result was as expected: com.domain.jira.ResultRow#7933f2c6.
I think maybe I'm missing some requirement for the class. Does it need to be defined in some special way to suggest to Velocity that certain members are usable in templates? Does Jira use some special funky version of Velocity that only works with certain objects?
I guess the answer is you cannot do what I was trying to do. You can call member methods but you can't access member variables, which means you'll need to add getters to your class. (Could've sworn I tried that. Ah well.)
Velocity does not expose fields, only methods. There are ways to change that:
You can create your own Uberspect class that allows access to public fields.
You can wrap the instance with a modified version of Velocity's FieldMethodizer that gives access to non-static fields.
You can add and use an instance of a "tool" class to your context, such as a subclass of VelocityTool's ClassTool.

Do I have to use webflows?

I want to collect the data for a domain class over a few forms. I'd like to initialise an instance of the domain, carry it through the form pages (assigning the collected data to the properties of the instance) and save the instance after the last form is completed successfully.
Is there a way to do this without webflows?
Is there a way to do this without webflows?
You can use hidden fields to accomplish this. But I may prefer you to use Webflows.
Here are some advantages of using Webflows:
1)You got two new scopes flow and conversation allows you to store variables, which are accessed within your flow
2)You have simple DSL to keep things tidy
3)Since there is a flow scope, you can do something like this:
flow.someThing = new YourClassName(params) //places object in flow scope
Keep in Mind:
1)If you use flow-scoped objects your class need to be implemented Serializable class.
2)And from Grails 1.2, you need to install Webflow plugin explicitly. Document says this:
From Grails 1.2 onwards Webflow is no longer in Grails core, so you
must install the Webflow plugin to use this feature: grails
install-plugin webflow
(see here).
As an alternative to Ant's comment, you could use the session, but storing a non-domain object or a simple Map. This will definitely lead to a lot of extra complexity, and the webflows do provide a lot of protection against accidental back-buttons, etc.
Rough idea:
in grails-app/domain
class Widget {
String name
int id
// constraints, etc
}
in grails-app/controllers
class WidgetCommand {
// setup your command
}
class WidgetController {
def savePage1 = { WidgetCommand cmd ->
// validate, etc
def widget = session.tempWidget ?: [:]
widget.putAll(cmd.properties)
session.tempWidget = widget
[widget: widget]
}
def savePage2 = { WidgetCommand cmd ->
// etc
}
def savePage3 = {
// or something similar here
def finalWidget = new Widget(session.tempWidget)
finalWidget.save()
}
}
You could try storing an actual domain object directly in memory, but I believe that will automatically be saved at session close if you are editing the object (as opposed to new ones), and you'll have to re-link it to the Hibernate session.

Managing multiple databases with NHibernate and Autofac

I thought I'd get this question out there while I noodled on a solution on my own.
After having built out the bulk of an application, I have a last minute requirement to support reading/writing to an additional database (2 total, no known others). I built the application using NHibernate, with Autofac supplying the DI/IoC components. FWIW, this resides in an ASP.NET MVC 2 app.
I have a generic repository class that takes an NHibernate session. Theoretically, I can continue to use this generic repository (IRepository<>) for the second database so long as the session that gets passed to it is spawned from an appropriate SessionFactory, right?
Well, when the app starts, Autofac does it's thing. With regards to the Session and SessionFactory, I have a module that states:
builder.Register(c => c.Resolve<ISessionFactory>().OpenSession())
.InstancePerMatchingLifetimeScope(WebLifetime.Request)
.OnActivated(e =>
{
e.Context.Resolve<TransactionManager>().CurrentTransaction = ((ISession)e.Instance).BeginTransaction();
});
builder.Register(c => ConfigureNHibernate())
.SingleInstance();
where ConfigureNHibernate(), which returns the base SessionFactory, looks like:
private ISessionFactory ConfigureNHibernate()
{
Configuration cfg = new Configuration().Configure();
cfg.AddAssembly(typeof(Entity).Assembly);
return cfg.Configure().BuildSessionFactory();
}
Currently, this is limited to just the one database. In any other NHib scenario, I'd likely shove instances of the separate SessionFactories into a hash, and retrieve them as needed. I don't want to have to re-architect the whole thing as we're fairly close to a major release. So, I'm guessing I need to modify at least the methods above so that I can independently configure two SessionFactories. My gray area is how I'll go about specifying the correct Factory be used with a specific repository (or at least for entities specific to that second database).
Anyone have experience with this scenario while using an IoC container and NHibernate in this manner?
EDIT
I've stubbed out a GetSessionFactory method that takes a configuration file path, checks for the existance of a matching SessionFactory in the HttpRuntime.Cache, creates a new instance if one doesn't already exist, and returns that SessionFactory. Now I still need to hammer out how to tell Autofac how and when to specify an appropriate config path. The new method looks like (borrowed heavily from Billy's 2006 post here):
private ISessionFactory GetSessionFactory(string sessionFactoryConfigPath)
{
Configuration cfg = null;
var sessionFactory = (ISessionFactory)HttpRuntime.Cache.Get(sessionFactoryConfigPath);
if (sessionFactory == null)
{
if (!File.Exists(sessionFactoryConfigPath))
throw new FileNotFoundException("The nhibernate configuration file at '" + sessionFactoryConfigPath + "' could not be found.");
cfg = new Configuration().Configure(sessionFactoryConfigPath);
sessionFactory = cfg.BuildSessionFactory();
if (sessionFactory == null)
{
throw new Exception("cfg.BuildSessionFactory() returned null.");
}
HttpRuntime.Cache.Add(sessionFactoryConfigPath, sessionFactory, null, DateTime.Now.AddDays(7), TimeSpan.Zero, System.Web.Caching.CacheItemPriority.High, null);
}
return sessionFactory;
}
I'm assuming that you want different types of entities to go into each database; if you want to keep the same kinds of entities in each database, check out AutofacContrib.Multitenant.
The two ingredients that can help with this scenario are:
Named services http://code.google.com/p/autofac/wiki/TypedNamedAndKeyedServices
Resolved parameter http://code.google.com/p/autofac/wiki/ResolveParameters (minimal docs on this one - the coming Autofac 2.4 release has some syntax sweeteners around this...)
First, use named services to refer to the two different databases. I'll call them "db1" and "db2". All of the components relating to the database, all the way up to the session, get registered with a name:
builder.Register(c => ConfigureDb1())
.Named<ISessionFactory>("db1")
.SingleInstance();
builder.Register(c => c.ResolveNamed<ISessionFactory>("db1").OpenSession())
.Named<ISession>("db1")
.InstancePerLifetimeScope();
// Same for "db2" and so-on.
Now, assuming you have a type NHibernateRepository<T> that accepts an ISession as its constructor parameter, and that you can write a function WhichDatabase(Type entityType) that returns either "db1" or "db2" when given the type of an entity.
We use a ResolvedParameter to dynamically choose the session based on the entity type.
builder.RegisterGeneric(typeof(NHibernateRepository<>))
.As(typeof(IRepository<>))
.WithParameter(new ResolvedParameter(
(pi, c) => pi.ParameterType == typeof(ISession),
(pi, c) => c.ResolveNamed<ISession>(
WhichDatabase(pi.Member.DeclaringType.GetGenericArguments()[0])));
(Warning - compiled and tested in Google Chrome ;))
Now, resolving IRepository<MyEntity> will select the appropriate session, and sessions will continue to be lazily initialised and correctly disposed by Autofac.
You will have to think carefully about transaction management of course.
Hope this does the trick!
NB

Using a grails/groovy class by reference

I'm trying to create my own CRUD controller in grails for the stuff that the scaffolding won't do.
Instead of maintaining code for a controller for each domain, I'd like to have one controller that can look after any domain for the generic CRUD calls.. as the only difference is the domain class name.
Using the example of domain class Job & Note
Instead of
Job.get(id)
Job.list()
def instance = new Job(params)
Note.get(id)
Note.list()
def instance = new Job(params)
I was thinking of
def someHandler = Job // configurable
someHandler.get(id)
someHandler.list()
def instance = new someHandler(params)
The first two static methods work fine (get, list) but creating a new instance does not.
Any pointers as to how to best do this.
Cheers
Call the default constructor using
def instance = someHandler.newInstance()
and the constructor for params using
def instance = someHandler.newInstance(params)
If you're not happy with the scaffolded controllers/views that Grails provides by default, and want to change them in a similar fashion for all domain classes, a better approach might be to simply edit the templates that are used to generate these controllers/views.
You can do this by running the script grails install-templates. This will create a number of files in the src/templates/scaffolding directory, each of which defines the template used to generate a scaffolded artifact.
Change these templates to create the controllers/views that you want. If you've already run grails generate-all for any domain classes, you'll need to run it again for those classes to update the existing scaffolding.

Resources