Wednesday, August 17, 2011

Setting Up WebDAV on Mac OSX Snow Leopard

After trying out several how-to's at various blogs, I finally was able to find one that "almost" worked.  I probably should mention that the first few tutorials I went through would have worked had I not misspelled a directory in the configuration file causing it not to be accessible.  The post below worked except the configuration for the httpd-dav.conf was slightly incorrect.  It shows "Dav On" outside of the <Directory> block, but should be inside the block.  After that everything worked.

http://geekfactor.charrington.com/2009/12/run-a-webdav-server-on-your-mac-to-sync-voodoopad-for-free

The setup that I was trying to achieve is for any user to be able to have read-only access to the WebDAV folders, but requires a valid user(one that is configured in the password file) in order to modify or delete anything.  To accomplish this a couple updates were required in the httpd-dav.conf in /etc/apache2/extras.

1. Add a LimitExcept block in the top level WebDAV directory.
    <LimitExcept GET OPTIONS PROPFIND>
        Require valid-user
    </LimitExcept>

What the above block will do is only allow guests to view the files and directories via a web browser and also connect to the WebDAV directory as a drive/folder.  The LimitExcept block disallows all HTTP command except the ones listed unless the user is valid and authenticated.

2. Add Options for Index

    Options +Indexes
    IndexIgnore ..
    IndexOptions -IconsAreLinks NameWidth=* FancyIndexing SuppressLastModified FoldersFirst
    IndexOrderDefault Ascending Name

The options above allow the files/directories to be seen via a web browser.

Update: WebDAV does not seem to work correctly in Windows 7.  A WebDAV client such as BitKinex is required.

Friday, July 15, 2011

Creating a Struts 2 Project Using Maven on Tomcat With IntelliJ IDEA

This post describes how to create a Java project using Struts 2 as the web framework, Maven as the build system to automatically deploy to Tomcat using IntelliJ IDEA 10 as the IDE.

Setting up Maven:
  • Download the latest version of Maven from http://maven.apache.org/download.html.
  • Install Maven by following the instructions at http://maven.apache.org/download.html#Installation.
Creating a Blank Struts 2 Project Using Maven
  • Change directory to the directory you want the project created in.
  • mvn archetype:generate -B -DgroupId=com.mycompany.myapp -DartifactId=my-app -DarchetypeGroupId=org.apache.struts -DarchetypeArtifactId=struts2-archetype-blank -DarchetypeVersion=<struts version ex. 2.2.3>
Creating the IDEA Project
  • File->New Project
  • Select the option "Create Java project from existing sources".  Then click "Next"
  • Enter a name and location for your project.  Then click "Next" 
  • Select "Do not create source directory" as the source directory was already created by Maven.
  • Click "Next" twice, then "Finish".
Associate Maven Project with IDEA
  • Go to"Maven" in the IDEA preferences.
  • For the Maven home directory value enter the location where you installed Maven ex. /usr/local/apache-maven/apache-maven-3.0.3
  • Click "Maven Projects" on the right side of the IDE.
  • Click  the "+" button to add a new Maven project.
  • Select the pom.xml that was created by Maven.
Add Struts and Dependencies Libraries
  • In IDEA go to the "Project Structure" menu item, click "Libraries" under "Project Settings".
  • Click the button "Attach Classes from Repository".
  • Enter org.apache.struts:struts-core:<struts version> ex. org.apache.struts:struts-core:2.2.3
  • Click "OK".
  • This will add the libraries to a lib folder in your IDEA project.
Add the Mojo Tomcat Deployment Plugin to the pom.xml
  • Add the following code snippet to the plugins section of the pom.xml.
  •             <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>tomcat-maven-plugin</artifactId>
                    <version>1.1</version>
                    <configuration>
                        <url>http://localhost:8080/manager/html</url>
                        <warFile>${project.build.directory}/${project.build.finalName}.war</warFile>
                        <server>tomcat-localhost</server>
                    </configuration>
                </plugin>
  • Note that the url and server values may need to be updated to reflect your installation.
  • In the Maven settings.xml add the following snippet to the "servers" section.
  •     <server>
          <id>tomcat-localhost</id>
          <username>username</username>
          <password>password</password>
        </server>
  • Note that the id must match the server name in the pom.xml and the username/password must be for the user that has the role "manager-gui".
  • To deploy to tomcat, in IDEA under the "Maven Projects" tab you should now see tomcat under "Plugins".  There you can select "tomcat:deploy" or "tomcat:redeploy" to deploy your application.

Monday, July 4, 2011

Drawing in CAShapeLayer versus CALayer

When drawing in a CAShapeLayer you can have a frame that has a width and height of 1 and drawing in the layer outside the frame and bounds will work as long as maskToBounds is not set to YES which is the default.  However, in a CALayer Quartz can only draw within the frame and bounds of the layer.  Stumbled across this when trying to create layers as small as possible to reduce memory usage and noticed that CAShapeLayer's rendered while CALayers did not render a drawing along the same path.

Thursday, June 2, 2011

iOS CALayers

After spending hours using Instruments to find a memory issue where real memory usage was hovering around 170-180MB on an app with many layers I finally was able to pinpoint the cause of the high memory utilization.  The issue was with the size of the CALayer frame's.  The application had about 40 large layers and each was the size of about two-thirds of the screen.  When reducing the size of the frames down to the minimum rectangle needed to display the content at that time, memory usage went down to 40-60MB.  In short, don't make layer frame's larger than absolutely needed. 

Monday, April 11, 2011

Compiling Static Framework for Use in Simulator and on iOS Device

After creating a static framework as described in the previous post it appears that the framework bundle that is viewable in the project pane of Xcode is only for the iphoneos version and not the iphonesimulator version even if the target is specified as the simulator.  Xcode still creates the iphonesimulator version when the simulator target is selected, however it is not viewable in Xcode.  In order to use the simulator version you will need to go to the filesystem.  Go to the same directory as the iphoneos version's parent directory and a directory for the simulator will also be there.  For example, the iphoneos version will be named something like Debug-iphoneos and the simulator will be named something like Debug-iphonesimulator.  Under those directories will be a directory containing your framework named <your product name>.framework, drag and drop that directory into your frameworks group in Xcode to use it.

Friday, April 8, 2011

Creating a Static Framework in Xcode 4

For iOS there is no template in Xcode to build a framework for iOS.  In order to get around this, you can create a Cocoa Static Library project and modify it so that you can develop and compile a static iOS Framework.  Using the post at "http://www.cocoanetics.com/2010/05/making-your-own-iphone-frameworks-in-xcode/" as a basis for writing this tutorial I was able to get it working and used it in a another project by following the steps outlined in this post.  This is the first library I've ever tried to create outside of Java so please feel free to chime in with any comments or corrections.

Create the Xcode project for the framework(skip if you already have an existing project):
- Open Xcode and create a new project (File->New->Project)
- Under the "Framework & Library" section under iOS select "Cocoa Touch Static Library".
- Under "Product Name" enter the name you want to call your framework.
- Click "Next" and "Create".

Add a Bundle target:
- Click the "Add Target" button at the bottom of the Xcode window.
- Select the "Bundle" template under Mac OS X.
- Give it the name of your framework.
- Click "Finish".

Set the Build Settings:
- Change the following properties to the values indicated below...
- Base SDK (replace the value with the appropriate iOS SDK version for your framework).
- Build Active Architecture Only = No
- Architecture and Valid Architectures = $(ARCHS_STANDARD_32_BIT)
- Mac OS X Deployment Target = Compiler Default
- Targeted Device Family (choose the appropriate iOS device i.e. iPhone/iPad)
- Dead Code Stripping = No
- Link With Standard Libraries = No
- Mach-O Type = Relocatable Object File
- Wrapper Extension = framework
- Generate Debug Symbols = No

Modify Info.plist file:
- Under your frameworks "Supporting Files" folder should be a file named <framework>-Info.plist.  Modify the "Bundle OS Type code to "FMWK"

Modify the Prefix.pch file:
- The generated Prefix.pch file under "Supporting Files" contains a reference to the Cocoa framework header file.  Remove that reference from the file.

Remove unnecessary frameworks from your project:
- Under the "Frameworks" folder delete frameworks such as Cocoa.framework and AppKit.framework that your project does not rely on.

Add frameworks required by your framework:
- If the project was created from a Cocoa template, the Cocoa framework is setup by default and not UIKIt which is required for iOS projects.
- Drag and drop any required frameworks such as UIKit under the "Frameworks" folder in your project pane.  In the dialog box that comes up uncheck "Copy items into destination group's folder (if needed)".
- UIKit should be in a folder similar to the following - /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/UIKit.framework

Add and develop your framework code files.

Add a new build phase for "Copy Headers":
- Select your framework target.
- Click the "Build Phases" tab.
- Click the "Add Build Phase" button and select "Add Copy Headers" from the pull-down menu.
- Under "Compile Sources" your source files should already be there, if not add them.
- Under "Link Binary With Libraries" remove any frameworks that might be present.
- Under "Copy Headers" add your .h  files to the section with the appropriate scope.  They can be "Public", "Private", or "Project".  You can drag them from the "Project" section to the "Public" or "Private" sections or from the project file pane.

Create Target for Universal Framework
-------------------------------------------------
- Create an "Aggregate" target named "<Framework Name> Universal Framework".
- Update the "Build Settings" by changing "SDKROOT" to "iphoneos".
- Click "Add Build Phase" and then "Add Run Script".  Copy the script below into the script area in "Run Script".  Be sure to update the "FMK_NAME" property to the name of your framework.

# Sets the target folders and the final framework product.
FMK_NAME=MyFramework
FMK_VERSION=A

# Install dir will be the final output to the framework.
# The following line create it in the root folder of the current project.
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework

# Working dir will be deleted after the framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework

# Building both architectures.
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator

# Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi

# Creates and renews the final product folder.
mkdir -p "${INSTALL_DIR}"
mkdir -p "${INSTALL_DIR}/Versions"
mkdir -p "${INSTALL_DIR}/Versions/${FMK_VERSION}"
mkdir -p "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources"
mkdir -p "${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers"

# Creates the internal links.
# It MUST uses relative path, otherwise will not work when the folder is copied/moved.
ln -s "${FMK_VERSION}" "${INSTALL_DIR}/Versions/Current"
ln -s "Versions/Current/Headers" "${INSTALL_DIR}/Headers"
ln -s "Versions/Current/Resources" "${INSTALL_DIR}/Resources"
ln -s "Versions/Current/${FMK_NAME}" "${INSTALL_DIR}/${FMK_NAME}"

# Copies the headers and resources files to the final product folder.
cp -R "${DEVICE_DIR}/Headers/" "${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/"

# Removes the binary and header from the resources folder.
rm -r "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/Headers" "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/${FMK_NAME}"

# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}"

rm -r "${WRK_DIR}"

Run the "MyApp Universal Framework" target to build the framework.  The framework bundle should now be under the "Products" folder of your project.  To use it in another project simply drag and drop it from your framework project to a folder in your project.

Hope this was helpful!