Thursday, January 12, 2017

Building Angular-CLI on Visual Studio Team Services ("VSTS")

With the advent of Angular-CLI, the making and maintaining of an Angular 2 project has become significantly easier.  Now, the project solution needs to become more "enterprise-y".  So, we'll add this to our VSTS to store our source code, build and deploy on our Azure subscription.  This post will focus on getting a successful build on VSTS.  This is what I mean by a successful build:

  • get/install all necessary modules from npmjs.com
  • get/install all necessary modules for angular-cli
  • perform an "ng build" on the angular-cli project
  • put the project's javascript bundles in a drop location for deployment

Creating the Build Definition

  1. On VSTS, navigate to Builds, click on the "New" button.
  2. Select "Visual Studio" for the build template.
  3. Select the Repository source.  I'm keeping my code in TFS, Observe, there are other options. 

  4. Click "Create"

Overview

At this point, let's take a look at what we're shooting for.  This seems like a hack, at this point.  But, it gets past some niggling errors.

Adding Task Runners to the Definition

  1. The first npm task runner will get/install all modules listed in your package.json. 
    1. npm command: install 
    2. arguments: (empty)
  2. The next npm task runner will get/install all modules that applies to angular-cli.  
    1. npm command: install
    2. UPDATE 3/8/17 arguments: -g @angular/cli
  3. UPDATE 3/8/17: Do another npm install 
    1. npm command: install 
    2. arguments: (empty)
  4. The last npm task runner will perform's angular-cli's "ng build" command.
    1. npm command: run-script
    2. arguments: build
  5. The previous step references a property in package.json.  Make sure this entry appears in that file.
  6. Let's put the projects bits somewhere.  Then, the Release process will have a pickup point to deploy our application.  The VSTS agent will find our bits in the "dist" folder.(Contents: **\dist)  It will place them in a folder called "drop" (Artifact Name: drop, Artifact Type: Server).
  7. Save the build definition

Summary

So, with those steps, you should be able to get source, build an angular-cli, build your project and deploy your output to a location for further processing.

Woof! 

Thursday, March 10, 2016

Angular 2 Image Link in ngFor Loop Or Make Empty Rows in Angular 2 For No Reason

If you're interested in dynamically generating an image link in say, a table, inside an Angular 2 project, take a look what's required.  If you have an image link in your table and you're wondering why it's displaying an extra "row" every time, then you've come to the right place.

<table>
           <tr *ngIf="angels.players" *ngFor="#player of angels.players">
                  <td>
                              First Name: {{player.firstName}}
                  </td>
                   <td>
                              Last Name: {{player.lastName}}
                  </td>
                   <td>
                              Jersey Number: {{player.jerseyNumber}}
                  </td>
                   <td>
                              <a>
                                     <img src=" ../../images/updateIcon.png " class="small                                                                                (click)="btnUpdatePlayerOnClick() " />
                             </a>
                  </td>
           </tr>
</table>

Don't do this unless you want an extra row in your table:

                   <td>
                              <img src=" ../../images/updateIcon.png " class="small                                                                                (click)="btnUpdatePlayerOnClick() " />
                  </td>

Woof!

Friday, October 9, 2015

ASP.Net MVC Namespace Compilation Error

Have you just created an ASP.Net MVC project from scratch?  You didn't like the default namespace because Visual Studio just applies the name of the project.  So, you change the namespace in the project properties, and your classes now have a nice looking namespace.

You run the debugger to take full stock of your beautiful application and this is what you get:

So, you hunt around your application, and, maybe, you find some of the default namespaces hanging around.  After making the appropriate changes, you run the debugger, again.  And, still, this error persists.  What gives?

Look here: Views/web.config.  You'll find the default namespace.  In my example, "LargeDachshund" is my default namespace, but I changed it to "com.BlogSpot.LargeDachshund" in my code.  Well, everywhere except here:

So change the namespace to your newly adopted version, and you're in business!

Woof!

Friday, August 7, 2015

Hibernate Red Herring #2315: @Version and the Transient Object Exception

I have a class, PitchingStat, that looks like this:

@Entity
@Table(name="PitchingStat", schema="hotDogs")
public class PitchingStat{

@Id
@Column(name="id")
private long id;

@Column(name="player_id", nullable=false)
private int playerId;

@Column(name="strikeOuts")
private int strikeOuts;

@ManyToOne
@JoinColumn(name="player_id", referencedColumnName="player_id")
private MLBPlayer mlbPlayer

.
.
.
}

It has a parent class nested in it, MLBPlayer.

@Entity
@Table(name="MLBPlayer", schema="hotDogs")
public class MLBPlayer{

@Id
@Column(name="player_id")
private int playerId;

@Column(name="created")
private Date created;

@Column(name="createdBy")
private String createdBy;

@Version
private long version;

.
.
.
}

If you implemented @Version, as I did, after the MLBPlayer table had been created and populated with data, then it's possible that you have encountered the transient object exception. Much of the MLBPlayer table's version column might have null values in some of the records. While this may seem innocuous at first blush, you obviously haven't worked with this Hibernate gem.

I attempted to save the PitchingStat object like this:

assume this MLBPitchingStat record is linked to an MLBPlayer record that has version = null.
MLBPitchingStat pitchingStat = getMLBPitchingStatByIdFromDb(pitchingSession, Id);

pitchingStat.setStrikeOuts(34);

pitchingSession.saveOrUpdate(pitchingStat);

Wham! Transient Object Exception: You need to save this transient entity, MLBPlayer, prior to saving the current object.

What happened? Apparently Hibernate has a fit over the version column's null value in the database. The version needs to be set in MLBPlayer, prior to saving the child record, MLBPitchingStat. So how do you go about resolving this?

Try this:
MLBPitchingStat pitchingStat = getMLBPitchingStatByIdFromDb(pitchingSession, Id);

pitchingStat.setStrikeOuts(34);

MLBPlayer mlbPlayer = pitchingStat.getMLBPlayer();

mlbPlayer.setVersion(1L);

pitchingStat.setMLBPlayer(mlbPlayer);

pitchingSession.saveOrUpdate(pitchingStat);

Now, you would think this would work. Wrong! Hibernate still has that fit over the version column's null value in the database. So what's the answer?

Do this:
In your database:
Update MLBPlayer as p
set p.version = 1
where p.version is null;

Problem solved.

Woof!

Thursday, June 18, 2015

Tomcat Logging: a Lesson in Half-Baked

Out of the box, Tomcat logging will output to catalina.out, until your hard drive is brought to its knees.  We won't hold our breath for the day that logrotate is implemented natively on those files in the logs folder.

Instead, here's how to logrotate that pesky catalina.out file.

1. In your Tomcat, navigate to .../bin/catalina.sh
2. Within catalina.sh, search for this keyword: "catalina.out"
3.  Now, by default, catalina.out will be set to "CATALINA_BASE"\logs\catalina.out
4.  LogRotate can't seem to operate in Tomcat's logs folder.  So, let's move the file somewhere else.  Let's say, /var/log/tomcat, for example.
5.  Next, let's configure a logrotate file that cron will operate on.
6.  Navigate to /etc/logrotate.d
7.  Create the file, "tomcat" and add the following configuration:
Based on this configuration, cron will copy and truncate the catalina.out file daily.  logrotate will keep seven days worth of catalina.out logs
8.  Let's save out a catalina.out file: sudo vi /var/log/tomcat/catalina.out
9.  To make things more user friendly, let's put a symbolic link in Tomcat's logs folder
10. Navigate to Tomcat's logs folder
11. Then: sudo ln -s /var/log/tomcat/catalina.out catalina.out

12. Finally, for all of this to take effect, we'll need to restart Tomcat
13. So, sudo ../bin/shutdown.sh
14. Then ../bin/startup.sh

Please note, cron has it's own notion when it'll perform the logrotate.  My system performs the operation at 3am.

Saturday, June 21, 2014

Eclipse and Tomcat, yeah they work, until you try and do stuff

I'm trying to implement Tomee on my existing project that currently uses Tomcat 7.  Tomee's website youtube video makes it deceptively simple to implement.  Funny how they never show the mess created when the real world meets open source.  In our case we always have existing projects, not a clean machine for demonstration.  So now you know the back story.

So, I mucked up my tomcat 7 configuration in eclipse.  I can set up Tomcat 7 in Eclipse' Preference>Servers.  But, i'm unable to attach it to my project.  Sisyphus had it easy compared to my feeble attempts to resurrect 7 in eclipse.  I found this link: Eclipse me with a butter knife.  The masochist in the message board did provide big help: just blow Tomcat configuration out.

Do this:
1. Close Eclipse
2. Navigate to  {workspace-directory}/.metadata/.plugins/org.eclipse.core.runtime/.settings
3. Delete the following two files:
    a. org.eclipse.wst.server.core.prefs
    b. org.eclipse.jst.server.tomcat.core.prefs
4. Restart Eclipse

Now, I can create my Tomcat 7 instance in Eclipse and my project can see it.

grrrr...

Wednesday, May 7, 2014

Eclipse with Tomcat Server: Whither Context.xml in Tomcat Connection Pooling

I'm implementing a web application with the following configuration:

  • Java 1.7
  • Hibernate 4
  • Tomcat 7
  • MySQL
Hibernate declares quite plainly that developers should avoid using its own connection pooling implementation for production systems.  The dearth of good documentation could paper a welcome mat.  Tomcat doesnt do much better.  

What's more, if you're using Eclipse to build the application and you want to debug on a tomcat server, how do you connect to MySQL without using Hibernate's connection pooling in hibernate.cfg.xml?  I cant provide the entire answer, but here's an important point for configuration:

The tomcat server in your Eclipse IDE has its own context.xml.  This is the file where you identify the database and its credentials to use by your applications.  If you assumed that the context.xml file located in your application's META-INF would be exercised, you'd be dead wrong.

Apparently, when you run your app in Eclipse, the attached Tomcat server only recognizes the context.xml file it has, and it ignores the one in the application.  Painful.

So do yourself a favor and add your database connection information into the server's context.xml file or feel the wrath of "org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot create JDBC driver of class '' for connect URL 'null'".