Tuesday, September 27, 2005

Location equivalency headaches

Bryan and I came up with this while trying solve migration and location/address integrity issues.

To define how multiple Location subordinates are equivalent, consider the following. The Location (country) USA has "states", "commonwealths", and a "district". It's neighbor to the north, Canada, has "provinces" and "territories". Likewise, the UK has "counties" or "post towns". On a formal level, these could all be called, "level 1 subordinates". If you have a Location table that defines a location by its type (and an id), then you could have the following:

Location
---------
id type name
-- ---- ----
1 country USA
2 country Canada
3 country UK
4 level1 Alabama
5 level1 Manitoba
6 level1 Southhampton
7 level1 Puerto Rico
8 level1 District of Columbia
9 country Mexico

LocationType
------------
id type
-- ----
1 country
2 level1
3 level2
4 level3
5 level4

Note, "level*" indicates a level of subordination. Using a LocationAssociation table you can build a hierarchy of locations and their subordinates.


For address creation, how could you equate like levels and provide an appropriate naming scheme in the context of the country? Here's one possible set of tables providing a solution:

First is a Subordinate Types table that defines the types you will use to identify subordinates (any level). This table could have a translatable counterpart that provided localized identifiers (I18n) per row, thus enabling translations for a single word, in multiple languages. (This is beneficial in the following model because it constrains translation to a single word and the context is derived based on equivalency relation.)

Subordinate Types
-----------------
id type
-- ----
1 state
2 province
3 territory
4 county
5 district
6 commonwealth

The Subordinate Equivalence table will relate a location, a locationType, specify if the row is a default (more on this in a moment), subordinateType, and a pointer to a localized string used to identify that component in the native country (locationId). This table realizes the equivalent nature of LocationTypes and SubordinateTypes in context of the owning location (usually country).

Subordinate Equivalence
-----------------------
id locationId locationType defaultBit subordinateType defaultLocalizedStringId
-- ---------- ------------ ---------- --------------- ------------------------
1 1 level1 1 state ->"State"
2 1 level1 0 district ->"District"
3 1 level1 0 commonwealth ->"Commonwealth"
4 2 level1 1 province ->"Province"
5 2 level1 0 territory ->"Territory"
6 3 level1 1 county ->"County"
7 3 level1 0 posttown ->"Post Town"
8 1 level2 1 county ->"County"
9 1 level3 1 city ->"City"
10 2 level3 1 city ->"City"
11 3 level4 1 city ->"City"
12 9 level1 1 state ->"Estado"
13 9 level3 1 city ->"Ciudad"

Thus, this table relates that "level3" is common across USA, Canada, UK, and Mexico. But, "level2" has no associated alternatives *in those countries*. Likewise, the word "county" is used twice, once to show a "county" is "level2" locationType in the USA. BUT, it also shows that it is a "level1" for the UK. So, the UK "county" could be considered equivalent to a USA "state" and Canadian "province" and "territory". This is quite helpful to know in address construction and UI presentation. The "defaultBit" shows which is the default subordinate type for that level, to display to the user.

I18n Benefits:

With the use of the FK to the Subordinate Types table, the i18n value of the subordinate type can be easily fetched. This is most helpful for countries that support multiple languages (ie. Canada or Switzerland).

Likewise, if a user in the USA wants to know what an "Estado" is, we can determine the equivalent through this table and provide an appropriate translation.

Monday, September 26, 2005

Lexmark printing

http://www.downloaddelivery.com/srfilecache/print-drivers-linux-glibc2-x86.deb
as root:
emerge deb2targz
execute deb2targz on the driver
execute the shell script located in usr/local/lexmark/setup.lexprint

execute lexprint to setup the printer

At this point the CUPS entry is created (once the printer is added) and you can print from anywhere that supports CUPS.

Oracle settings

This is what I had to add to my .bashrc to get Oracle drivers/sqlplus working:
#oracle stuff
ORACLE_BASE=/home/russ/apps/oracle
ORACLE_HOME=$ORACLE_BASE/10
TNS_ADMIN=$ORACLE_HOME/tnsnames
export ORACLE_HOME TNS_ADMIN ORACLE_BASE
LD_LIBRARY_PATH=$ORACLE_HOME/basic-client:$ORACLE_HOME/sql-client
export LD_LIBRARY_PATH
SQLPLUS=$ORACLE_HOME/sql-client/sqlplus

Wednesday, September 21, 2005

Opera Adblock. thanks to the wiki

http://nontroppo.org/wiki/OperaPythonAdblock

Here's how I finally got "AdBlock" functionality working in Opera.

In my opera6.ini under "[Image Link Popup Menu]" and "[Image Popup Menu]:

Item, "Destroy image python" = Copy image address & Execute program,"/home/russ/.opera/adblock.py","%c" & Select user CSS file,1 & Deselect user CSS file, 1 & Select user CSS file,1 & Deselect user CSS file, 1

Where adblock.py (universally executable) is:

#!/usr/bin/python
import sys, os

BLOCK_CSS_FILE="/home/russ/.opera/adblock.css"

# read current CSS
try:
cssFile=open(BLOCK_CSS_FILE,"r")
except:
cssStr="\n"
else:
cssStr=cssFile.read()
cssFile.close()

# write new CSS
cssFile=open(BLOCK_CSS_FILE,"w")
if len(sys.argv)==2:
cssFile.writelines('img[src="'+sys.argv[1]+'"]')
elif len(sys.argv)==3:
cssFile.writelines(sys.argv[2]+'"'+sys.argv[1]+'"]')
elif len(sys.argv)==5:
cssFile.writelines(sys.argv[2]+'['+sys.argv[3]+sys.argv[4]+'"'+sys.argv[1]+'"]')
elif len(sys.argv)==4:
cssFile.writelines(sys.argv[2]+'['+sys.argv[3]+'='+'"'+sys.argv[1]+'"]')

if (cssStr=="\n")|(cssStr==""):
cssFile.writelines('\n{display:none !important;}')
else:
cssFile.writelines(',\n')
cssFile.writelines(cssStr)

cssFile.close()


And now that Opera is free without the ad banner, imports FireFox bookmarks, and can now block images this may be a long-term relationship. It's fast and so far I like it.

Forgot that this is also present in opera6.ini:

[Author Display Mode]
Author Font and Colors=1
User Font and Colors=0
User Link Settings=1
Author CSS=1
User CSS=1

[User Display Mode]
User CSS=1
User Link Settings=1
Author CSS=1
Author Font and Colors=1
User Font and Colors=0

[Local CSS Files]
Name 12=Adblock
File 12=adblock.css
Name 13=Overlay
File 13=overlay.css
Active 13=0
Active 12=1

Saturday, September 17, 2005

Divs, Iframes, and Windows rendering

Been a long weekend debugging a bunch of pop-ins that we're using that were hosed because of IE's rendering of Selects. The divs that were being popped-in overlapped some selects are were thus subject to the nasty effect of the Selects bleeding through. I was trying to glean code from the DatePicker.js in Tapestry, but the way it automatically generates the coordinates for the calendar was a little too tricky for what we need. And, I couldn't get it to work right (after 2-3 hours!). Thankfully it was helpful enough to illustrate the necessity of generating an IFrame (which takes rendering precedence) under the div. I had that working except in some cases the iframe was out of synch with the div so the locations appear hosed.

Anyhow, long story short, thanks to this blog from Joe King at MS, it clicked that I was 90% of the way there but was missing only a couple small things. After another hour of tweaking, I have a solution.

Assuming you have a DIV that is your pop-in already placed where you want it to show, it's just a matter of adding the following code and calling "hideOrShowPop" (stupid, yes, I should rename it):


function hideOrShowPop(id){
var popin= document.getElementById(id);
var idToFetch = id + "Active";
var popinActive = document.getElementById(idToFetch);

if(popin.style.visibility=="hidden"){
handlePop(id);
}
else{
popin.style.visibility="hidden";

var clone = document.getElementById("clone"+id);
if(clone != null){
clone.style.visibility="hidden";
clone.removeNode(true);
}
}
}

function handlePop(id){
var popinDiv = document.getElementById(id);
var anchorNode = document.getElementById(id+"Anchor");

popinDiv.style.visibility="visible";
popinDiv.style.display="block";

var cloneDiv = popinDiv.cloneNode(false);
//this is for figuring out how to put the popin ANYWHERE on the screen, currently not working
//var anchorPoint = getLocationPoint(anchorNode);
//popinDiv.style.top = anchorPoint.y;
//popinDiv.style.left = anchorPoint.x;

var width = parseInt(popinDiv.style.width);
var height = parseInt(popinDiv.style.height);

cloneDiv.id = "clone" + id;
try{
cloneDiv.zIndex="3";
cloneDiv.innerHTML = "";
popinDiv.parentNode.appendChild(cloneDiv);
popinDiv.parentNode.appendChild(popinDiv);
} catch(e){
alert("Popin exception caused by id: " + idToFetch + " or " + id);
if(ie)
alert(e.description);
else
alert(e);
}
}


So the code clones the div, then sets the inner node of the cloned div to an iframe. Lastly it's appended to whomever owns the original div, and then the original div is appended after the clone.

Now I can go to bed.

Friday, September 16, 2005

Firefox HTTP sniffer

Credit to Todd T. for this fantastic find:
http://tamperdata.mozdev.org/installation.html

Easily view HTTP traffic from your browser AND edit it before it's sent.

Thursday, September 15, 2005

16080x1050, finally!

Modeline "1680x1050" 147.14 1680 1784 1968 2256 1050 1051 1054 1087

Tapestry: DatePIcker, SSL, and IE

Final solution was adding "src=https:Home.html" to the IFrame, since Home.html was relative. This fixed the annoying security issues, and it left the IFrame in place (so no Selects will ever be hosed when a DatePicker is near). What a dang pain.

Here are the posts I wrote along the way (most recent first):

Branding myself a hasty hoser, the previously posted code did not work (my test page was cached with a previous attempt).

So, for real this time, the fix is: commenting out that line of code for generating the IFrame. Of course, if you have a dropdown underneath it then you'll probably want it, but that's a tradeoff explicitly awaiting IE developers. This fix is quick and dirty, but it works for me since we don't have any Selects near DatePickers.

http://support.microsoft.com/default.aspx?scid=kb;en-us;177378
" However, IFRAME tries to draw on top of SELECT because it is last in the order. To prevent this, the value of the SELECT element's z-index must be greater than that of the IFRAME, or the SELECT element must be last in the list to ensure that the element always draws on top of the IFRAME when the z-indexes are the same. Because of this, z-indexing similar content can be difficult."

IFrame security covered here (Dec 04, which explains why the DatePicker was working fine in IE last year at this time):
http://www.microsoft.com/technet/security/bulletin/ms04-040.mspx

Hopefully I'm done with this topic, apologies for the repeated posts,
-RR-

-----------------
Thanks to this thread, http://thread.gmane.org/gmane.comp.java.tapestry.user/13528, I have changed DatePicker.js:

(previous line)
underDiv.innerHTML = "";

(new code)
underDiv.innerHTML = "";

Works wonderfully.

On 9/15/05, RR wrote:


>opening the DatePicker window yields a security warning in Internet
>Explorer when using an SSL connection. The message is the infamous "This
>page contains both

secure and nonsecure items. Do you want to display
>the non

secure items?".

http://article.gmane.org/gmane.comp.java.tapestry.user/7271/match=+secure+items


In Tapestry 3 I'm having the same problem as above -- wondering if anyone else has experienced it and found a solution? This thread is old and I haven't found anything else related.

What I've tried (and without resolution):

1)added my cert as a trusted cert
2)changed the component render to place an onclick in the image instead of wrapping it as an anchor
3)explicitly added "https:" in front of the rendered src attribute on the img.

Any other ideas out there?

Java TCP Tunnel analyzer

Very slick little GUI in soap-2.3.jar (http://www.ibiblio.org/maven/soap/jars/) for setting up a proxy and monitoring TCP traffic. Basic usage is:

java -cp soap-2.3.jar org.apache.soap.util.net.TcpTunnelGui 9999 localhost 8080

Where "9999" is the local socket, localhost is the destination host to monitor, "8080" is the port to monitor on the destination host. So, to monitor your communication with Gmail you could execute: java -cp soap-2.3.jar org.apache.soap.util.net.TcpTunnelGui 9999 gmail.google.com 80. Then, in your browser, you'd use the following URL:

http://localhost:9999/

However, this will only work if you don't require an HTTP proxy.

Likewise with https with a local secure link and server:
java -cp soap-2.3.jar org.apache.soap.util.net.TcpTunnelGui 8888 localhost 8443
and
https://localhost:8888/

Wednesday, September 14, 2005

3550 entry

Educational goals:
a) Finish my CS degree before I'm 30. Hopefully going to happen in the time frame I'd like. Work, kids, and other responsibilities have outweighed my educational pursuits since I began working full-time in 2000.

b) Obtain a Masters degree in something. While I'd like to think that I'd focus on CS studies once I'm done at UVSC, my wife is pretty sure that we'll be taking a break from school for a while. It'd be all too convient if UVSC offered a Masters program by the time I'm done with my under-grad.

Some interests:

  • Linux

  • Programming

  • Being with my kids

  • Software Development

  • Soccer

  • U.S. History

  • Reading (mostly non-fiction right now)

Friday, September 09, 2005

Tapestry render solution

The solution to my render rant a couple days back has been tedious, but not difficult. Started out with:

/**
* Simple interface declaring required properties for a protected component to (en/dis)abling a component render and its disable(d) state.
*
*/
public interface IProtectedComponent{

/**
* Flag for allowing component render.
*
* @return a Boolean value
*/
public boolean getAllowRender();

}


Then I wrapped all of the default Tapestry components we're using, for example:

/**
* A protected PropertySelection component only rendered if allowedRender is true.
*
*/
public abstract class ProtectedPropertySelection extends PropertySelection implements IProtectedComponent{

protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle){
if(getAllowRender() == true){
super.renderComponent(writer, cycle);
}
}


Did this for:
Any
Button
Checkbox
DatePicker
Insert
DirectLink
LinkSubmit
PageLink
PropertySelection
Submit
TextFiel
ValidField

Then, in the base class pageBeginRender, added the following:

for(Iterator componentIter = components.keySet().iterator(); componentIter.hasNext();){
String componentId = (String)componentIter.next();
IComponent component = getComponent(componentId);
IBinding elementId = component.getBinding(ELEMENT_IDENTIFIER);

if(IProtectedComponent.class.isAssignableFrom(component.getClass())){
IProtectedComponent protectedComponent = (IProtectedComponent)component;
if(elementId != null){
//resolve rights to component
//boolean updateOrExecute = canAccess(elementId, CRUDAction.UPDATE);
boolean updateOrExecute = true;
if(! updateOrExecute){
//boolean canRead = canAccess(elementId, CRUDAction.READ);
boolean canRead = false;
if(!canRead){
//do not render the component
component.setProperty(ELEMENT_ALLOW_RENDER, "false");
component.setProperty(ELEMENT_DISABLE, Boolean.TRUE);
}
else{
//Render the component, but make it disabled
component.setProperty(ELEMENT_ALLOW_RENDER, "true");
component.setProperty(ELEMENT_DISABLE, Boolean.TRUE);
}
}
else{
//Render the component normally
component.setProperty(ELEMENT_ALLOW_RENDER, Boolean.TRUE);
component.setProperty(ELEMENT_DISABLE, Boolean.FALSE);

}
}
}
}

So, I'm basically cycling through all of the components and changing state based upon id attribute and rights to the element. By the time renderComponent is called, the allowRender and disabled properties are set. Thus, this ensures the component is handled properly based upon user rights associated to the id.

Wednesday, September 07, 2005

Tapestry rant

Okay, time to spout off about Tapestry. Situation is this: let's say you have a page with a bunch of components. And this page happens to contain *secure* elements. Requirements state that the component can be viewable/read-only, updateable, or not present. Security model dictates, some time before render, what the state of each component should be. So, next issue is rendering the components. Should be as easy as updating the "disabled" attribute for the read-only, and eliminating/removing/not-rendering the components that are unauthorized.

What are the reasons for Tapestry completely hosing the easibility of this process?! This would be cake in XMLC or Wicket!

1. Components must be defined prior to render. Which means, you need to have the "disabled" parameter set to false on *every* single component you want to protect, at build-time. It is a pain to add a "binding" on at run-time and highly discouraged (http://article.gmane.org/gmane.comp.java.tapestry.user/25209).

2. Tapestry is incapable of removing components at render time. You don't have access to the DOM, you can't set a flag, nothing. I should clarify, this is the case for a) all default Tapestry components b) you can sort of work around this by wrapping the component in a Conditional component.

3. Tapestry default components do not allow render flags. In conjunction with issue #2, you can't just set a flag informing Tapestry to NOT render the component.

So, why does this really tick me off? Because I have many pages on which I now need to implement security (aforementioned implementation). I cannot, out-of-the-box, do what I need. I must go through each component and add the "disabled" attribute (only 130+ of them). I must choose to wrap the components in Conditionals if I don't want them rendered. IMO, this is a ton of work and really defeats the purpose of dynamic page generation.

My acceptable is solution is to go through and create wrapper components for each of the Tapestry components we're using. I'll add a default "disabled" attribute that I can hose with at run-time (so the user doesn't have to add it specifically) and a flag that determines whether the component should render. This is going to take more time than I likely have. Wish I knew about this issues months ago, I *may* have reconsidered my choice of web application framework.

One alternative, Java Server Faces, does exactly what I want in its UIComponentBase:
http://java.sun.com/j2ee/javaserverfaces/1.1_01/docs/api/javax/faces/component/UIComponentBase.html#UIComponentBase()

In conclusion, the more I work with Tapestry the more I feel like my hand is being held and while it provides some nifty aspects (reusable components, form validation), I can accomplish essentially the same thing in some other frameworks. The more I look into JSF, the more I'm realizing its value....