Glen Mazza's Weblog

Main | Next page »

https://web-gmazza.rhcloud.com/blog/date/20160124 Sunday January 24, 2016

TightBlog: January 2015 Update

Still plugging along, with particular gains in the Spring configuration, page caching, and blog model used by the Velocity rendering. One functional improvement was to pull out the Google Analytics tracker code on blog author previews so they won't show up on GA stats pages. The GitHub Issues List notes 16 issues open and 133 closed. Of the Java source files, 16 more have been removed, dropping TightBlog to 260 classes compared to the 493 in Apache Roller I forked it from. The contributors page notes almost 46,000 lines have been removed from the codebase through 188 commits.

https://web-gmazza.rhcloud.com/blog/date/20151224 Thursday December 24, 2015

TightBlog: December 2015 update

Since my update last month, I've been able to pull out an additional 21 Java source files, dropping TightBlog to 276 total compared to Roller's 493, a nice 44% drop. Other files, such as XMLs and JSPs have also been removed if not to the same degree, as many of those simplifications I had already gotten done while on the Roller team. The GitHub Issues List notes 121 issues closed and 18 still open. Mainly still code refactoring (I'm shifting more to optimizing the SQL queries now -- identifying and removing redundant/unnecessary calls, inefficient calls, etc.) Biggest functional improvement has been in field validation and input field whitespace trimming. I also have been following changes to the Apache Roller project, incorporating those I like into Tightblog as well.

https://web-gmazza.rhcloud.com/blog/date/20151213 Sunday December 13, 2015

Working with TightBlog source code

Note: TightBlog is an unfinished fork of Apache Roller without full rebranding having been finished, so there remain several Roller references below.

This entry explains how to set up a development environment and process for working on the Java-based TightBlog blog server. The tools below are the ones I use, some are optional some (such as preferred IDE or database to use) can be modified to your preference.

Tool list for programming TightBlog:

ToolBefore proceeding, make sure you can...
JDK 1.8Activate "java" and "javac" from any folder in a command-prompt window
Intellij IDEA (I use the free community edition)Can activate the application from a command-line.
Apache MavenActivate "mvn" from any folder in a terminal window
Command-line git clientRun "git" from any folder in a terminal window
Standalone Tomcat 8Can start and view Tomcat from http://localhost:8080
Apache Derby databaseCan activate ij (for Derby) from any folder in a command-prompt window. Note: See below instructions for using MySQL or PostgreSQL instead.
Firefox Web BrowserOptional; used for running Selenium tests without needing to activate Tomcat
SQL Query tool such as SquirrelSQLOptional but recommended; used for querying the TightBlog database instance.
  1. Fork TightBlog and add any desired additional themes - Do a git clone git@github.com:gmazza/tightblog.git from the command-line window. You can also make a fork within GitHub to work from your own account. If you have any of custom blog themes to add, place them in the src/main/webapp/themes folder prior to building TightBlog. Make sure TightBlog build (including JUnit tests) runs successfully before proceeding further.

  2. Prepare database and (optional) mail configuration - Follow the short Chapter 5 and Chapter 6, Sections 1-4 of the Roller Install Guide (ODT). Chapter 5 provides the few commands needed to configure an empty MySQL, PostgreSQL, or Derby database and Chapter 6 the configuration of the roller-custom.properties file, optional Mail configuration, and the required Mail and JDBC JARs that will be needed in Tomcat's lib folder. The test roller-config.properties file that I have in my Tomcat lib folder is as follows:

    # Any properties placed below overrides TightBlog default settings defined in
    # the roller.properties file embedded within the TightBlog WAR, and should be 
    # stored in the CATALINA_HOME/lib folder for Tomcat.
    
    installation.type=auto
    mediafiles.storage.dir=/home/gmazza/work/tightblog-dbs/mediafiles
    search.index.dir=/home/gmazza/work/tightblog-dbs/searchindex
    
    # TightBlog file and logging level
    log4j.appender.roller.File=${catalina.base}/logs/roller-tomcat.log
    log4j.logger.org.apache.roller=INFO
    
    #Derby
    database.configurationType=jdbc
    database.jdbc.driverClass=org.apache.derby.jdbc.ClientDriver
    database.jdbc.connectionURL=jdbc:derby://localhost:1527//home/gmazza/work/tightblog-dbs/MYROLLERDB
    database.jdbc.username=app
    database.jdbc.password=app
    
    # EclipseLink debugging (filepath cannot be simplified via ${catalina.base} as above)
    eclipselink.logging.file=/home/gmazza/work/apache-tomcat-8.0.30/logs/eclipselink-tomcat.log
    eclipselink.logging.level=FINER
    
    # Mail config (See Roller Install Guide)
    mail.configurationType=jndi
    mail.jndi.name=mail/Session
    

    Before moving on to the next step, best to deploy the app/target/roller.war to your Tomcat webapps directory, start Tomcat and confirm you can run the application at http://localhost:8080/roller. This is an important one-time check to ensure your database, roller-custom.properties file, Tomcat, and Roller WAR are all properly configured, and once confirmed you should be in good shape for all subsequent coding and debugging. If any deployment problems, make sure you've reviewed Chapters 5 and 6 of the Install Guide.

  3. Create a script to start development with everything needed - For efficient start-up I've created a hacktb.sh script that opens up all needed windows and applications at once instead of having me needing to do so manually each time I start development. A simplified version of my hacktb.sh is as follows and explained below:

    hackroller.sh:

    gnome-terminal --geometry=132x24 \
       --tab-with-profile=HasTitle --title "TB Trunk" --working-directory ~/work/tightblog \
       --tab-with-profile=HasTitle --title "TB Trunk2" --working-directory ~/work/tightblog -e "bash -c \"echo -Dmaven.surefire.debug; exec bash\"" \
       --tab-with-profile=HasTitle --title "Servlet Container" \
       --tab-with-profile=HasTitle --title "IntellijIDEA" -e "bash -c \"sh idea*/bin/idea.sh; exec bash\"" \
       --tab-with-profile=HasTitle --title "Derby Network" --working-directory $DERBY_HOME/bin -e "bash -c \"startNetworkServer; exec bash\"" \
       --tab-with-profile=HasTitle --title "GEdit" -e "gedit worklog.txt hacktb.sh $CATALINA_HOME/lib/roller-custom.properties $CATALINA_HOME/logs/catalina.out $CATALINA_HOME/logs/roller-tomcat.log `find $CATALINA_HOME/logs/localhost*.log` $CATALINA_HOME/logs/eclipselink-tomcat.log tightblog/app/target/roller.log tightblog/app/target/eclipselink.log " \
       --tab -e "dolphin --geometry=600x500+1+1 tightblog-dbs tightblog $CATALINA_HOME" \
       --tab -e "google-chrome https://github.com/gmazza/tightblog/issues http://localhost:8080/roller" \
       --tab-with-profile=HasTitle --title "SquirrelSQL" --working-directory ~/work/squirrel-sql-3.7 -e "bash -c \"sh squirrel-sql.sh; exec bash\""
    

    The above script opens a multitab Console window which in turn opens a few separate application windows. In particular:

    • I open two terminal tabs pointing to the TightBlog code. This allows me to build TightBlog from one terminal while reviewing my changes (using commands git status and git diff, etc.) in the second window. I echo the -Dmaven.surefire.debug in the second tab as a reminder of the Maven string to add during JUnit test debugging (covered below).
    • I have a separate "ServletContainer" tab open to my home folder for manual activation of servlet containers (Tomcat normally) or other applications from the command line. I don't need this as often due to the copy.sh script (discussed below) I now use.
    • I use a tab for starting IntelliJ IDEA.
    • I use Derby's Network mode (startNetworkServer) instead of its Embedded mode so the database can be accessed by multiple JVM's (one by Tomcat and the other by Squirrel SQL).
    • I open the multi-tab GEdit text editor with several files that are handy for me during development:
      • worklog.txt - A scratchpad file of TODO notes, commands, etc. that I keep for personal use between coding sessions.
      • hacktb.sh - The very script above, I keep handy in case I need to make adjustments or additions to it.
      • roller-custom.properties - The configuration file discussed above and used by all TightBlog deployments to my standalone Tomcat. Changes I made here are activated on the next Tomcat restart.
      • catalina.out, roller-tomcat.log, localhost*.log, eclipselink-tomcat.log - These are logging files filled by Tomcat and/or TightBlog during running, usually very important for debugging as error logging usually gets written to one of these files. When you see terse "System" or similar errors reported by TightBlog in the web browser be sure to check these files for the error in detail.
      • roller.log, eclipselink.log - These files are under TightBlog's target directory and are populated during JUnit test running via the Maven test phase, as discussed below.
    • Dolphin - A multitab file browser that I have opened to the TightBlog trunk code, database files, and Tomcat folders for easy access to files.
    • Firefox - Here I pre-open tabs to the TighBlog website and default webpage location for TightBlog once it's deployed to Tomcat.
    • SquirrelSQL - Commented-out by default but used when I wish to query the TightBlog database to see the values that TightBlog is reading/writing. SquirrelSQL will need your database's JDBC JAR added to it as well as have the connection information configured in roller-custom.properties.

    For scripts such as the above make sure there's no whitespace after the ending "\" on each line (error messages will pop up otherwise), and use a leading # (as shown above for SquirrelSQL) for actions you wish to disable by default. The $CATALINA_HOME specified above, as usual, is the base folder for your standalone Tomcat installation. In addition to the above configuration, you may wish to keep handy the Roller trunk documentation, kept in OpenOffice format in the Roller/docs folder or online.

  4. How to build and deploy to local Tomcat - After a successful mvn clean install from the TightBlog trunk folder, I run this copy.sh shell script that I keep in that folder:

    fuser -k 8080/tcp 8009/tcp 8005/tcp
    rm -r $CATALINA_HOME/webapps/roller
    cp ./app/target/roller.war $CATALINA_HOME/webapps
    rm $CATALINA_HOME/logs/*.log
    rm $CATALINA_HOME/logs/catalina.out
    $CATALINA_HOME/bin/startup.sh
    

    For rapid iteration when I don't need to run the tests each time, I simplify my build and deploy process to a single line: mvn clean install -Dmaven.test.skip ; sh copy.sh.

    The above file first kills the Tomcat instance (via fuser -k), deletes the previous expanded TightBlog webapp directory on the Tomcat instance and copies the latest created Roller WAR over, and clears all the logs before finally restarting Tomcat with the new WAR. The new TightBlog will be accessible at http://localhost:8080/roller again using the same $CATALINA_HOME/lib/roller-config.properties and database (i.e., all database-stored information including test blog data created will be immediately picked up by the new Roller WAR.)

  5. How to debug on local Tomcat - Learning to debug from your IDE any webapp running locally on standalone Tomcat is frequently vital when troubleshooting and thankfully simple to do. First, add to your Tomcat CATALINA_OPTS environment variable:

    export CATALINA_OPTS=$CATALINA_OPTS" -Xdebug -Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=n"
    

    Then from IntelliJ IDEA (or Eclipse), go to menu item Run -> Edit Configurations, add a Remote Configuration with a name of your choice and accepting the given defaults, and select OK. If TightBlog is already running on Tomcat, debugging can be activated at any time by setting breakpoints in the code that the TightBlog app would be activating, selecting menu item Run --> Debug {debug config name}, and then proceed with any needed code tracing.

  6. How to debug unit tests - To activate a specific TightBlog JUnit test, navigate to the tightblog/app folder and run mvn test -Dtest=TestClassName#OptionalTestMethodName, as explained in the Maven Surefire Plugin documentation. To debug (code trace) the JUnit test within your IDE, add the -Dmaven.surefire.debug setting, set breakpoints in your IDE within code called by the tests and have it listen to port 5005 as before.

    Files to read: When running the JUnit tests, besides the Surefire results in the target/surefire-reports folder the target/roller.log file provides logging of the temporary in-process TightBlog instance. Also, to determine any potential SQL/JPA problems, EclipseLink JPA logging can be activated, with the output file also in the target folder, by uncommenting the eclipselink.logging.* properties in the app/src/test/roller-custom.properties file.

  7. How to run Selenium tests - TightBlog's Selenium tests test very basic functionality (setting up a blog and saving a blog entry) but can sometimes serve as a quick sanity check that minor, last-second source code changes did not cripple the application. Navigating to the trunk/it-selenium folder and running mvn clean install will cause a temporary instance of TightBlog to activate that is subsequently used by Selenium to run its tests in Firefox. For these tests, none of the database or Tomcat configuration created above will be used, instead TightBlog will be running an embedded Jetty and a temporary (in-memory) Derby database, and shut down once Selenium is finished.

https://web-gmazza.rhcloud.com/blog/date/20151124 Tuesday November 24, 2015

TightBlog: November 2015 update

Since my update last month, I've been able to pull out an additional 35 Java source files, dropping TightBlog to 297 total compared to Roller's 493. The GitHub Issues List notes 114 issues closed and 21 still open. The application still isn't ready until the open issues are closed, but I'll keep working on zeroing out the remaining open issues.

The code simplification/shrinkage comes from normal refactoring and code modernization, embracing the Spring framework, using JAXB over JDOM, and having a higher threshold than Apache Roller of which functionality to retain. Generally speaking, any functionality that fewer than say 3% of bloggers would use gets tossed out, and functionality that perhaps up to 10% would use but would not be a deal-breaker if TightBlog didn't provide has also been removed. This threshold has dropped me to perhaps about 20-30 features that I can focus on making solid for bloggers. When there is too much seldom-used functionality to maintain, core functionality starts to suffer, causing people who might have liked the extended functionality to turn away from the product anyway due to its substandard core, a situation I'm trying to avoid with TightBlog.

https://web-gmazza.rhcloud.com/blog/date/20151115 Sunday November 15, 2015

Pink Slips at Disney. But First, Training Foreign Replacements.

Sold Out Book

Journalist Michelle Malkin and Center for Immigration Studies fellow John Miano have teamed together to offer a new book Sold Out. It offers a critique of the various foreign worker visas offered by the federal government and its consequences on American workers. I just got the book yesterday and am still in its early stages but would highly recommend it for American IT professionals wishing to learn more about the consequences of these programs or (for those already well aware) just wanting to thank and support the authors for raising publicity about this issue during an election year. Happy to note at the time of this writing that the book is #1 on Amazon's Government and Management bestseller list.

https://web-gmazza.rhcloud.com/blog/date/20151105 Thursday November 05, 2015

Letter to the Arlington County board via fitness membership fees (Update: With County Response)

My county has a website form residents can use to submit questions, comments and concerns, which I've used three times in the past five years. The county runs fitness centers of which I'm a member. This morning I submitted the below concern (slightly polished for grammar :) about the reduced cost passes for non-county residents 55 and over:

Hello, I'm [in my mid-40's] and a long-time taxpaying Arlington County resident as well as an Arlington County gym member. When I buy my annual County fitness center pass, I pay the $195 rate as a county resident, much less than the $558 charged to non-residents because residents pay Arlington County taxes and as much of Parks & Rec is supported by taxpayer dollars we should be discounted. No problems there, neighboring jurisdictions do the same thing.

The county, via its 55+ Gold Pass program, has recently dropped the qualification age from 62 to 55, any resident 55 or over needs to just pay $60. OK. But non-residents 55+ who aren't paying Arlington taxes have to pay just $90, a mere $30 more and less than half the $195 that I need to pay. That benefit seems too disproportionate to be giving to non-taxpaying non-county residents--should I really have to be paying $195 while a relatively youthful 55-year old Fairfax County resident just has to pay $90?

55 is hardly retirement age, many of those people are at the top of their financial situation at that time, and giving such a benefit to 55+ county residents must come at a significant price both to county taxpayers who have to subsidize the shortfall in fees and paying county members whose memberships would be cheaper if they didn't have to cover this subsidy. So be it, though, we take care of our senior residents. But asking taxpayers and gym members to pay more to be subsidizing *non-county* residents as young as 55 seems an unfair burden to ask. I'd like the county to raise the minimum age for non-county residents back to 62, and/or alternatively retain the same $195/$558 resident/non-resident ratio for the senior passes ($60 for residents, $172 for non-residents.) Gyms cost money to run, and non-residents should be expected to pay more to cover the difference that they're not paying in county taxes.

I've checked the Fairfax County Parks and Recreation website and they give no senior discount to people outside of their jurisdiction, they just take care of their own and then only when they reach 65. Alexandria does cover at age 55, but only a 20% discount and again only for city residents. Likewise, Arlington County reduced fee memberships correctly just cover Arlington residents, taxpayers don't have to support non-residents for that.

This rate is also bad for the County for another reason -- each of the fitness centers have a limited number of aerobic machines, the more you fill up those machines due to heavy subsidies of non-county residents, the $195 payers get upset because the machines are never available and instead go to private gyms that aren't that much more expensive for them. The percentage of those using the gym being full payers is going to drop as a result, with the lost gym revenue requiring more county subsidies in order to be supporting people who live outside the county's jurisdiction.

Update 12/31/2015, I got a response from the County today:

Dear Mr. Mazza,

I am writing to you on behalf of Arlington County Board Chair Mary Hynes. Thank you for sharing your concerns about the 55+ Gold Pass fee for non-residents and the change in age eligibility for senior adult rates. The issues you mentioned are actually part of a number of adjustments made to senior adult programs during the last budget cycle.

Each year, the Arlington County Board approves the schedule of fees and charges for the Department of Parks and Recreation as part of the annual budget process. In Fiscal Year 2016, fees for senior adult programs were realigned for consistency across the County programs. Prior to this, all persons 55+ were eligible for programs offered through the Office of Senior Adults. However, various other programs applied an age discount to 62+. As a policy change, the age of eligibility for all senior programs and discounts offered through the Department of Parks and Recreation is now 55+.

It is Arlington County policy to allow non-residents to use County facilities and programs and to require non-residents to pay a surcharge on top of the base participation fee. This surcharge varies based on the type of program. In the case of the 55+ Pass, non-residents are charged 50% more than residents. Non-residents, however, never receive a fee reduction (which is only available to residents with financial need).

The County is committed to offering programs for seniors to remain healthy and to age in place. As part of this mission, we are always looking at ways to further this focus. As such, the base fee for this 55+ Gold Pass is set at only $60 for an individual pass and the surcharge added to that for non-residents is the additional 50%.

Formerly, we offered a 55+ pass with limited fitness pass options, along with a separate senior fitness-only membership. Research indicated that very few seniors purchased the senior fitness-only membership. The vast majority of seniors purchased the 55+ Pass that included a variety of senior program options, including limited access to some fitness centers. Research also indicated that many of the seniors with the 55+ Pass were interested in expanded fitness access and were willing to pay for it. As our goal is to develop programs that support the interests of our community, it was decided that we would have two senior passes and eliminate the senior fitness-only membership. We kept the same fee for the 55+ Pass ($20) and created the 55+ Gold Pass ($60), which provides the benefits of the 55+ Pass plus access to our fitness centers whenever they are open.

As with all of our programs, we will continue to review what Arlington County is providing and adjust as needed. As of December 29, an additional 2,136 Arlington County residents have purchased a pass. Only 146 (6% of the total) non-residents have signed up for the program; the percent of non-residents has not really changed since we adjusted the program. Since the new pass went into effect, we have been monitoring fitness room usage and have seen no spikes in attendance leading to overcrowding. We will continue to monitor.

Our annual budget review is coming up, and again, as always, fees will be reviewed and adjustments made as appropriate. I hope this background is helpful and allows you to see our strategy to encourage more Arlington seniors to be active and engaged.

Please let us know if you have any further questions.

Michael R. Peter, MPA
Director of Budget and Finance
Arlington County Department of Parks and Recreation

https://web-gmazza.rhcloud.com/blog/date/20151031 Saturday October 31, 2015

"Monster Mash" Will Get You

From The Miami News, October 6, 1962:

Rock 'n' roll and the twist have finally come to grips with Horror and the result is a startling eruption in the record-buying field. Now it's spreading to the screen and television.

A little .45 disc titled "Monster Mash," rocketing within a few weeks into a spot among the top 10 sellers, seizes upon weird species from the Frankenstein laboratory, man-made creatures who shake off their electrodes and, to the tune of a shudder-packed production number, stomp around the graveyard in a wild new dance.

The "Monster Mash" has become an overnight hit in Los Angeles ballrooms, and two film studios and at least one TV network are angling for rights to its use for specialty insertions in movies and air shows.

Chief proponent of the new order is Bobby (Boris) Pickett who, like his recording sponsor, Gary Paxton, is bewildered by the smash reception the record has won. Hurriedly, they have marshaled a musical troupe for an invasion of eastern cities, with Boston scheduled as the first stop.

To a set of frightening Karloff-toned lyrics ("I was working in my lab late one night when my eyes beheld an eerie sight...my Monster from his slab began to rise...and suddenly to my surprise...he did the mash. He did the Monster Mash!") dancers the country over may soon be stomping and flailing their arms into a new epidemic--a slow-beat dance which Pickett feels will come as a welcome relief from the swift torturous movements of the twist.

How did Pickett happen on horror as the stepping stone to a new dance madness?

"The door was wide open," replied the young singer, who leads the song and dancers himself. "Horror pictures always have been popular and it seemed funny no one hit upon them for a dance until now. We just drove into a red-hot vacuum."

https://web-gmazza.rhcloud.com/blog/date/20151025 Sunday October 25, 2015

Tightblog taking shape

I forked Apache Roller last May after about two-and-a-half years volunteering on the project, calling my fork "Tightblog" to emphasize the amount of streamlining I wished to do to it. As of today, Tightblog still isn't ready, the GitHub issues list reports 97 issues closed and 23 open. Although there have been a few enhancements added (a notes field for blog entries, configurable anchor, alt text and title for media files, and much easier to set up planet functionality), I'm still pretty much cleaning out the old before I can move on to modernizing the remaining core.

Since forking Roller, I've been able to reduce the number of Java source files from 493 to 332--with more to go!--while keeping average file size about the same. The running application feels zippier. The number of database tables has fallen from 33 to 18 plus one view. The data model is fairly stable now, I don't see any more tables being added or removed, although a few columns may still be adjusted here and there. A table-by-table comparison between Tightblog and present production Apache Roller 5.1.2:

Tightblog (column list)Apache Roller 5.1.2 (column list)
weblogger_properties
weblogger_user

user_weblog_role
weblog


weblog_template
weblog_template_rendition

blogroll_link
weblog_category
weblog_entry
weblog_entry_tag
weblog_entry_tag_agg (view)
weblog_entry_comment
ping_target
weblog_ping_target

media_directory
media_file



planet
planet_subscription

planet_subscription_entry
roller_properties
roller_user
userrole
roller_permission
weblog
entryattribute
roller_hitcounts
weblog_custom_template
custom_template_rendition
bookmark_folder
bookmark
weblogcategory
weblogentry
roller_weblogentrytag
roller_weblogentrytagagg
roller_comment
pingtarget
autoping
pingqueueentry
roller_mediafiledir
roller_mediafile
roller_mediafiletag
rag_properties
rag_planet
rag_group
rag_subscription
rag_group_subscription
rag_entry
newsfeed
roller_audit_log
roller_tasklock
roller_oauthconsumer
roller_oauthaccessor

I believe that the streamlined data model I settled on for Tightblog will provide a reliable, wobble-free foundation for upper layers of the application without sacrificing important functionality. As you can see from the table names, I'm taking care not to make references to the project name within the data model as I'd like to make it smoother for others to rebrand and/or incorporate this Apache-licensed work into their own projects.

https://web-gmazza.rhcloud.com/blog/date/20150627 Saturday June 27, 2015

Git & GitHub Notes

  1. For ease, fork the repo on GitHub and clone your fork rather than the main repo, then

    git remote add upstream git@github.com:githubaccountname/githubrepo.git
    to link to main repo.

  2. git push origin branchName -- "origin" refers to the fork (here, one's own, else can be upstream or any other created via git remote)

  3. To switch between branches locally, git checkout <branch name> (use git branch to see a list); to check out a new branch based on the one you're currently in, git checkout -b <new branch name>

  4. git fetch upstream [branch or remote branch:local branch] - update pointers to latest code, git merge afterwards (or git pull to do both) to update local code. If any automated merge failures, right-click Git->Resolve Conflicts from IntelliJ to resolve manually.

  5. To place your changes on one branch above those from another: (from your branch): git fetch as above, then

    git rebase [branch name to retrieve from]
    , then
    git push origin brname -f
    to update GitHub fork.
  6. Recovering from an accidental pull: SO #1, SO #2. Another possibility: git rebase -i HEAD~xxx to supposedly squash the commits, but I instead removed all unwanted commits from the pull. Then git rebase to bring in actual wanted branch.

  7. To pull a different branch to your local machine:

    git remote add upstream git@github.com:githubaccountname/githubrepo.git
    git fetch upstream
    git co upstream/release/branchname
    git co -b [newBranchNameHere]
    
  8. To checkout a tag.

  9. To check out a coworker's branch:

    git remote add coworkerFork https://github.com/coworkerAcct/Repo.git
    git fetch coworkerFork hisBranch:newNameForYourLocalBranch
    
  10. In GitHub pull requests, use ``` or ```json to format code (JSON)

  11. In PR reviews, use : to bring up icons.

  12. Deleting a branch:

    git branch -D branchnames...

  13. List of repos presently watching: https://github.com/watching

  14. Squashing commits:

    git log
    to find number of commits to squash,
    git rebase -i HEAD~X
    (X is number of commits). 1st page: mark all but first commit "s" for squash, 2nd page, edit common commit message. Standard editor: Ctrl-K to remove lines, Ctrl-X to save. Then
    git push origin brName -f
    to update remote.

  15. git cherry-pick to copy commits from one place to another. Applying a commit from one branch to another:

    git log to copy sha of commit you want to merge
    git fetch upstream to download all available branches
    git co -b mynewbranch
    git pull upstream {branchYouWantToAddPRTo}
    git cherry-pick { sha value} -m 1
    git push origin mynewbranch
  16. How to merge a PR against one fork into your own
  17. Wanting to create a new branch without committing changes first:
    git stash, git checkout -b newBranch, git stash pop
  18. Undoing changes:
    git checkout <branch_copying_from> -- <file_to_reset>
  19. branch rewinding - another method for combining commits when the work was not done on a separate branch.
  20. JQuery Commits and Pull Requests Guide
  21. Checking out an older git version (snapshot)
  22. Adding Git Aliases -- simplify terminal window commands
  23. Efficient way to do commits:
    git log --oneline --decorate
  24. Which release contains a commit? git fetch --all followed by git tag --contains (hash)
  25. Amending commit messages

https://web-gmazza.rhcloud.com/blog/date/20141124 Monday November 24, 2014

Using UsernameToken security with Apache CXF

This tutorial modifies the CXF version of the WSDL-first DoubleIt web service to include WS-Security with UsernameTokens. This profile should be used with transport-layer encryption (i.e., SSL) as a minimum to ensure the username and password are encrypted at least between the client and the first recipient node. Note the X.509 or SAML token approach would be more appropriate instead if any of cases below apply:

  • Clients need to sign the request to guard against it being altered in transit
  • There are intermediary nodes between client and service that would be unencrypting the message (and hence able to read its contents) before forwarding it on to the next node
  • The web service provider has incomplete nonce and timestamp support necessary to guard against replay attacks. CXF has implemented such caching since version 2.6, and it also appears supported with Metro.

CXF provides two main options for adding UsernameToken security headers, both of which will be covered below: WS-SecurityPolicy and manual CXF interceptors. The former relies on the WSDL already having WS-SecurityPolicy elements defined within it to obtain the security requirements. Use the manual CXF interceptor approach when security is not defined in the WSDL or more customized control of the security header construction is desired.

Note one difference between CXF's UsernameToken implementation and Metro's is that the former requires explicit service-side callback handlers to validate passwords while the latter, for the Tomcat and the GlassFish server, will validate against container usernames and passwords if no service-side callback handler is declared. However, CXF provides a JAASLoginInterceptor for container-based authentication.

The finished tutorial source code can be obtained from GitHub by using either the download ZIP button or git clone -v git://github.com/gmazza/blog-samples.git command. The download is configured to use WS-SecurityPolicy, if desired make the adjustments specified below to switch to the CXF interceptor approach.

  1. Implement SSL without basic authentication for the web service. This is the same as Step #1 of the Metro/UsernameToken guide.

  2. Include additional Maven dependencies to handle security processing. The following dependency will need to be added to the project-level pom.xml to activate security processing.

    <dependency>
       <groupId>org.apache.cxf</groupId>
       <artifactId>cxf-rt-ws-security</artifactId>
       <version>${cxf.version}</version>
    </dependency>
    

    Also, since we'll be adding a Spring cxf.xml configuration file to the client to declare the security parameters, we'll need to add a Spring dependency to the client/pom.xml. (See notes at the bottom for a non-Spring way of doing client configuration.) While CXF is relatively flexible with the version of Spring that you use, to determine the optimal (tested) version of Spring for your version of CXF, go to the tags folder of the CXF source repository, select your version of CXF, and under that folder select the folder named "parent" and open its pom.xml. Search for the cxf.spring.version variable to determine the version to use.

    <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-context</artifactId>
       <version>${spring.version}</version>
    </dependency>
    
  3. Configure the client to provide the user and password. We'll be introducing a Spring-based cxf.xml configuration file, presently configured for the WS-SecurityPolicy approach but can be switched over to the CXF interceptor approach by following the comments given below in this source file.

    Next supply the password CallbackHandler that was listed in the SOAP client above. Place this class in the same package as the SOAP client:

    package client;
    
    import java.io.IOException;
    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.callback.UnsupportedCallbackException;
    import org.apache.wss4j.common.ext.WSPasswordCallback;
    
    public class ClientPasswordCallback implements CallbackHandler {
    
        public void handle(Callback[] callbacks) throws IOException, 
                UnsupportedCallbackException {
            WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
    
            if ("joe".equals(pc.getIdentifier())) {
                pc.setPassword("joespassword");
            } // else {...} - can add more users, access DB, etc.
        }
    }
    
  4. Add the WS-SecurityPolicy statements to the WSDL. This has already been done in the Service WSDL in the source code download, which uses the WS-Policy statements created in the Metro UsernameToken tutorial. CXF interceptor method only: We'll need to use a Policy-free WSDL, so remove this DoubleIt.wsdl and rename the Policy-free DoubleItInterceptorMethod.txt found in the service submodule resources folder to DoubleIt.wsdl (it's the same WSDL from the standard DoubleIt tutorial.)

  5. Configure the service provider to authenticate the username and password tokens. Here we'll need to modify the cxf-servlet.xml configuration file from Step #6 of the WSDL-first tutorial to add either the CXF inbound interceptor or WS-SecurityPolicy configuration information (not both.) Replace the previous cxf-servlet.xml file with the following, after modifying it based on your security implementation preference:

    Once done we'll need to add the new server-side password callback class referenced above, which provides the correct password for a user, which the CXF framework uses to compare with what is supplied in the client request. Place the following ServerPasswordCallback class to the same package as the service's DoubleItPortTypeImpl SEI implementation class:

    package service;
    
    import java.io.IOException;
    
    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.callback.UnsupportedCallbackException;
    import org.apache.wss4j.common.ext.WSPasswordCallback;
    
    public class ServerPasswordCallback implements CallbackHandler {
    
        public void handle(Callback[] callbacks) throws IOException,
                UnsupportedCallbackException {
            WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
    
            if ("joe".equals(pc.getIdentifier())) {
               pc.setPassword("joespassword"); 
            }
        }
    }
    

    You can now compile and redeploy the web service from the DoubleIt base folder.

  6. Test the client. Run the client as shown in the DoubleIt tutorial. Best to test also with incorrect usernames and passwords to ensure the web service provider is catching these errors.

    You can view the headers being added to the SOAP request if you temporarily switch your web service back to non-SSL usage. This can be done by updating the web.xml and URL within the WSDL, and additionally if you're using WS-SecurityPolicy, removing any WSDL element declaring a requirement for SSL. Once done you can either use Wireshark or activate logging within your WSClient class to see the unencrypted SOAP messages. Running the client from a terminal window will show results similar to the following:

    Oct 1, 2011 7:47:34 PM
    org.apache.cxf.interceptor.AbstractLoggingInterceptor log
    INFO: Outbound
    Message
    ---------------------------
    ID: 1
    Address:
    http://localhost:8080/doubleit/services/doubleit
    Encoding: UTF-8
    Content-Type: text/xml
    Headers: {Accept=[*/*], SOAPAction=[""]}
    Payload:
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
        <soap:Header>
            <wsse:Security
                xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
                soap:mustUnderstand="1">
                <wsse:UsernameToken wsu:Id="UsernameToken-1">
                    <wsse:Username>joe</wsse:Username>
                    <wsse:Password
                        Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">joespassword</wsse:Password>
                </wsse:UsernameToken>
            </wsse:Security>
        </soap:Header>
        <soap:Body>
            <ns2:DoubleIt xmlns:ns2="http://www.example.org/schema/DoubleIt">
                <numberToDouble>10</numberToDouble>
            </ns2:DoubleIt>
        </soap:Body>
    </soap:Envelope>
    --------------------------------------
    Oct 1, 2011 7:47:34 PM
    org.apache.cxf.interceptor.AbstractLoggingInterceptor log
    INFO: Inbound
    Message
    ----------------------------
    ID: 1
    Response-Code: 200
    Encoding:
    UTF-8
    Content-Type: text/xml;charset=UTF-8
    Headers: {Content-Length=[238],
    content-type=[text/xml;charset=UTF-8], Date=[Sat, 01 Oct 2011 23:47:34
    GMT], Server=[Apache-Coyote/1.1]}
    Payload:
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
        <soap:Body>
            <ns2:DoubleItResponse xmlns:ns2="http://www.example.org/schema/DoubleIt">
                <doubledNumber>20</doubledNumber>
            </ns2:DoubleItResponse>
        </soap:Body>
    </soap:Envelope>
    --------------------------------------
    The number 10 doubled is 20
    

    If you do this, remember to switch back to SSL for production usage.

Notes

If desired, you can avoid introducing a Spring dependency in the client by not using a cxf.xml configuration file and instead declaring security using the Java API in the client's WSClient class. A sample alteration demonstrating both the WS-SecurityPolicy and CXF interceptor approaches is as follows:

...
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.handler.WSHandlerConstants;
...

public class WSClient {
   
    public static void main(String[] args) {
        DoubleItService service = new DoubleItService();
        DoubleItPortType port = service.getDoubleItPort();

        // WS-SecurityPolicy configuration method
/*
        Map ctx = ((BindingProvider)port).getRequestContext();
        ctx.put("ws-security.username", "joe");
        ctx.put("ws-security.callback-handler", ClientPasswordCallback.class.getName());
        // instead of above line can also do:
        // ctx.put("ws-security.password", "joespassword");
*/
        // Alternative CXF interceptor config method
/*
        Client client = org.apache.cxf.frontend.ClientProxy.getClient(port);
        Endpoint cxfEndpoint = client.getEndpoint();
        Map outProps = new HashMap();
        outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
        outProps.put(WSHandlerConstants.USER, "joe");
        outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
        outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,
            ClientPasswordCallback.class.getName());
            
        WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
        cxfEndpoint.getOutInterceptors().add(wssOut);
*/        
        ...


Valid HTML! Valid CSS!

This is a personal weblog, I do not speak for my employer.