Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials

7019 Articles
article-image-solving-nlp-problem-keras-part-2
Sasank Chilamkurthy
13 Oct 2016
6 min read
Save for later

Solving an NLP Problem with Keras, Part 2

Sasank Chilamkurthy
13 Oct 2016
6 min read
In this two-part post series, we are solving a Natural Language Processing (NLP) problem with Keras. In Part 1, we covered the problem and the ATIS dataset we are using. We also went over the word embeddings (mapping words to a vector) along with Recurrent Neural Networks that solve complicated word tagging problems. We passed the word embedding sequence as input into the RNN and we then started coding that up. Now, it is time in this post to start loading the data. Loading Data Let's load the data using data.load.atisfull(). It will download the data the first time it is run. Words and labels are encoded as indexes to a vocabulary. This vocabulary is stored in w2idx and labels2idx. import numpy as np import data.load train_set, valid_set, dicts = data.load.atisfull() w2idx, labels2idx = dicts['words2idx'], dicts['labels2idx'] train_x, _, train_label = train_set val_x, _, val_label = valid_set # Create index to word/label dicts idx2w = {w2idx[k]:k for k in w2idx} idx2la = {labels2idx[k]:k for k in labels2idx} # For conlleval script words_train = [ list(map(lambda x: idx2w[x], w)) for w in train_x] labels_train = [ list(map(lambda x: idx2la[x], y)) for y in train_label] words_val = [ list(map(lambda x: idx2w[x], w)) for w in val_x] labels_val = [ list(map(lambda x: idx2la[x], y)) for y in val_label] n_classes = len(idx2la) n_vocab = len(idx2w) Let's print an example sentence and label: print("Example sentence : {}".format(words_train[0])) print("Encoded form: {}".format(train_x[0])) print() print("It's label : {}".format(labels_train[0])) print("Encoded form: {}".format(train_label[0])) Here is the output: Example sentence : ['i', 'want', 'to', 'fly', 'from', 'boston', 'at', 'DIGITDIGITDIGIT', 'am', 'and', 'arrive', 'in', 'denver', 'at', 'DIGITDIGITDIGITDIGIT', 'in', 'the', 'morning'] Encoded form: [232 542 502 196 208 77 62 10 35 40 58 234 137 62 11 234 481 321] It's label : ['O', 'O', 'O', 'O', 'O', 'B-fromloc.city_name', 'O', 'B-depart_time.time', 'I-depart_time.time', 'O', 'O', 'O', 'B-toloc.city_name', 'O', 'B-arrive_time.time', 'O', 'O', 'B-arrive_time.period_of_day'] Encoded form: [126 126 126 126 126 48 126 35 99 126 126 126 78 126 14 126 126 12] Keras model Next, we define the Keras model. Keras has an inbuilt Embedding layer for word embeddings. It expects integer indices. SimpleRNN is the recurrent neural network layer described in Part 1. We will have to use TimeDistributed to pass the output of RNN Ot At each time step: t To a fully connected layer. Otherwise, the output at the final time step will be passed on to the next layer. from keras.models import Sequential from keras.layers.embeddings import Embedding from keras.layers.recurrent import SimpleRNN from keras.layers.core import Dense, Dropout from keras.layers.wrappers import TimeDistributed from keras.layers import Convolution1D model = Sequential() model.add(Embedding(n_vocab,100)) model.add(Dropout(0.25)) model.add(SimpleRNN(100,return_sequences=True)) model.add(TimeDistributed(Dense(n_classes, activation='softmax'))) model.compile('rmsprop', 'categorical_crossentropy') Training Now, let's start training our model. We will pass each sentence as a batch to the model. We cannot use model.fit() because it expects all of the sentences to be the same size. We will therefore use model.train_on_batch(). Training is very fast, since the dataset is relatively small. Each epoch takes 20 seconds on my Macbook Air. import progressbar n_epochs = 30 for i in range(n_epochs): print("Training epoch {}".format(i)) bar = progressbar.ProgressBar(max_value=len(train_x)) for n_batch, sent in bar(enumerate(train_x)): label = train_label[n_batch] # Make labels one hot label = np.eye(n_classes)[label][np.newaxis,:] # View each sentence as a batch sent = sent[np.newaxis,:] if sent.shape[1] >1: #ignore 1 word sentences model.train_on_batch(sent, label) Evaluation To measure the accuracy of the model, we use model.predict_on_batch() and metrics.accuracy.conlleval(). from metrics.accuracy import conlleval labels_pred_val = [] bar = progressbar.ProgressBar(max_value=len(val_x)) for n_batch, sent in bar(enumerate(val_x)): label = val_label[n_batch] label = np.eye(n_classes)[label][np.newaxis,:] sent = sent[np.newaxis,:] pred = model.predict_on_batch(sent) pred = np.argmax(pred,-1)[0] labels_pred_val.append(pred) labels_pred_val = [ list(map(lambda x: idx2la[x], y)) for y in labels_pred_val] con_dict = conlleval(labels_pred_val, labels_val, words_val, 'measure.txt') print('Precision = {}, Recall = {}, F1 = {}'.format( con_dict['r'], con_dict['p'], con_dict['f1'])) With this model, I get a 92.36 F1 Score. Precision = 92.07, Recall = 92.66, F1 = 92.36 Note that for the sake of brevity, I've not shown the logging part of the code. Loggging losses and accuracies are an important part of coding up an model. An improved model (described in the next section) with logging is at main.py. You can run it as : $ python main.py Improvements One drawback with our current model is that there is no look ahead, that is, output: ot This depends only on the current and previous words, but not on the words next to it. You can imagine clues about the properties of the current word that are also held by the next word. Lookahead can easily be implemented by having a convolutional layer before RNN and word embeddings: model = Sequential() model.add(Embedding(n_vocab,100)) model.add(Convolution1D(128, 5, border_mode='same', activation='relu')) model.add(Dropout(0.25)) model.add(GRU(100,return_sequences=True)) model.add(TimeDistributed(Dense(n_classes, activation='softmax'))) model.compile('rmsprop', 'categorical_crossentropy') With this improved model, I get a 94.90F1 Score! Conclusion In this two-part post series, you learned about word embeddings and RNNs. We applied these to an NLP problem: ATIS. We also made an improvement to our model. To improve the model further, you can try using word embeddings learned on a large site like Wikipedia. Also, there are variants of RNNs such as LSTM or GRU that can be experimented with. About the author Sasank Chilamkurthy works at Fractal Analytics. His work involves deep learning  on medical images obtained from radiology and pathology. He is mainly  interested in computer vision.
Read more
  • 0
  • 0
  • 3262

article-image-creating-dialplan-asterisk-16-part-2
Packt
27 Oct 2009
14 min read
Save for later

Creating a Dialplan in Asterisk 1.6: Part 2

Packt
27 Oct 2009
14 min read
Advanced Call Distribution What exactly is Advanced Call Distribution ? Many phone systems tout this feature, but most do not adequately define what it means. Basically, it refers to using call queues, parking calls for another user to answer, and Direct Inward Dialing (DID). So that we keep our focus, we will look at each of these elements individually. Call queues We have already configured call queues through the /etc/asterisk/queues.conf file. As we go through how we're going to use our queues, we may decide we want to change the way our queues are configured. There is absolutely no problem with changing the configuration so that it more accurately reflects our needs. Just remember that we need to issue a reload on the Asterisk console, or type #asterisk –r –x reload at the command line. The power and flexibility of other ACD systems can be matched or exceeded by Asterisk. As we evaluate our needs, we should remember that configuring a single aspect of Asterisk sometimes requires changes to more than one file. For example, queues will be configured both in the queues.conf file and the extensions.conf file. We will discuss how to set up extensions.conf to give us the desired result. When dealing with call queues, we need to think about the two types of users we have. First, we have the caller who calls in and waits in the queue for the next agent. We can think of this person as our customer. Next, we have the agents who work the queue. We can think of these people as our users. As a business, we have to decide what we want our customers' experience to be. Our call queue can make it sound like a phone is ringing. Or we can use music on hold while the customer waits. We can also announce call position and estimated wait time if we want to. When we place customers in a queue, we use the Queue application. To place a caller in the queue named bob, we would use something like: exten => 1000,1,Queue(bob) Suppose we have an operator's extension. As Ollie the operator may have more than one call at a time, we decide to give him a call queue. His calls are always about a minute long. The customers waiting for him are going to be there because they got lost in a system of menus. His queue will be named operator. In this instance, we will choose to have the customer hear the ring, so they will believe they are about to be helped. The sound of ringing should not last more than about a minute. We will not announce call queue length because our customer should not know that he or she is in a queue. The entry for this queue would be: exten => 0,1,Queue(operator|tr) Notice our use of options. Options for the queue application include: t: Allow the user to transfer the customer. T: Allow the customer to transfer the user. d: This is a data-quality call. H: Allow the customer to hang up by hitting *. n: Do not retry on timeout. The next step in the dialplan will be executed. r: Give the customer the ringing sound instead of music on hold. Thus, we told the Queue application to make the customer hear the ring, and the user (Ollie) the ability to transfer calls (as he's the operator). Now, suppose we have Rebecca, the receptionist at SIP phone 1006. When Ollie goes to the bathroom, we want our poor lost customers to be routed to her. So we could use the following in our extensions.conf file: exten => 0,1,Queue(operator|trn)exten => 0,2,Dial(SIP/1006) Now, Rebecca had better answer this. Until she does, the phone will continue to ring. Notice that this call will never end up in Rebecca's voicemail, as it is not transferred to her extension, but instead dials her phone directly. We have adequately addressed the customer's experience. But now we need to look at how our users will join and leave the queue. Previously, we discussed the power and flexibility of using agents in queues. As with most things in Asterisk, there are many ways we can associate members to queues. The three main ways are—statically, dynamically, and by using agents. Our first option is to have members statically assigned to the queue. In order to do this, we use the member directive in the queues.conf file. This is most helpful when we have a queue with fixed members, such as a switchboard queue. Our second option is to allow members to log in dynamically. We do this through the AddQueueMember application. An example of this would be: exten => 8101,1,AddQueueMember(myqueue|SIP/1001) Whenever anybody dials extension 8101, the telephone handset SIP/1001 would be added to the queue named myqueue. All that we would have to do is define a login extension for every member of every queue. What happens when this member no longer wishes to be in the queue? We use the RemoveQueueMember application, like this: exten => 8201,1,RemoveQueueMember(myqueue|SIP/1001) With this configuration, whenever anybody dials extension 8201, the telephone handset at SIP/1001 is removed. Again, we would have to define a logout extension for each member of the queue. Suppose we did not wish to define a login and logout extension for each member. We have the option of leaving off the interface (SIP/1001 in the previous example) and having Asterisk use our current extension. While this is very useful, Asterisk does not always use the right value. However, if it works for all extensions that need to be in the queue, we would only have to define one login and one logout per queue. The code would look like: exten => 8101,1,AddQueueMember(myqueue)exten => 8201,1,RemoveQueueMember(myqueue) This is better than having to define a login and logout for each member of each queue, but sometimes users are not good at remembering multiple extensions to dial. The AddQueueMember application will jump to priority n+101 if that interface is already a member of the queue. Therefore, we could define an extension like: exten => 8101,1,Answerexten => 8101,2,AddQueueMember(myqueue)exten => 8101,3,Playback(agent-loginok)exten => 8101,4,Hangupexten => 8101,103,RemoveQueueMember(myqueue)exten => 8101,102,Playback(agent-loggedoff)exten => 8101,105,Hangup When we define it this way, a user dialing extension 8101 is logged in if not already a member of the queue, or logged out if in the queue. Also, we added a confirmation to the action, so that the user can know if they are now in or out of the queue. Notice that before we could use the Playback application, we had to answer the call. If we have a lot of these, we could define a macro extension, like: [macro-queueloginout]exten => s,1,Answerexten => s,2,AddQueueMember(${ARG1})exten => s,3,Playback(agent-loginok)exten => s,4,Hangupexten => s,103,RemoveQueueMember(${ARG1})exten => s,104,Playback(agent-loggedoff)exten => s,105,Hangup. . .[default]exten => 8101,1,Macro(queueloginout|queue1)exten => 8102,1,Macro(queueloginout|queue2)exten => 8103,1,Macro(queueloginout|queue3) And thus we see that using a macro will save us five lines in our extensions.conf for every queue after the first. This is how we can add queue members dynamically. Our final option for adding queue members is by using Asterisk's agent settings. We were able to define agents in /etc/asterisk/agents.conf. We create an agent by defining an ID and a password, and listing the agent's name. In the queues.conf, we could define agents as members of queues. Calls will not be sent to agents unless they are logged in. In this way, queues can be both dynamic and static—they are static when we do not change the members of the queues, but dynamic when calls will go to different handsets based upon which agents are logged in. There are two main types of agents in this world. There are the archetypical large call center agents who work with a headset and never hear rings, and there are the lower-volume agents whose phone rings each time a call comes in. Asterisk has the flexibility to handle both types of agents, even in the same queue. First, imagine a huge call center that takes millions of phone calls per day. Each agent is in multiple queues, and we have set each queue to use an announcement at the beginning of calls to let the agent know which queue the call is coming in from. As employees arrive for their shift, they sit down at an empty station, plug in their headset, and log in. Each employee will hear music in between calls, and then hear a beep, and the call will be connected. To accomplish this, we use the line: exten => 8001,1,AgentLogin Through the normal login, the call is kept active the whole time. The agents will logout by hanging up the phone. This allows large call centers to be quieter, as the distraction of ringing phones will be removed. It also allows for more efficient answering of lines, as the time required to pick up the phone is eliminated. When our users arrive at work and wish to log in, they call extension 8001, where they are prompted for their agent ID, password, and then an extension number at which they will take calls. This is how Asterisk knows how to reach them. Our agents can log out when using AgentCallbackLogin by going through the same procedure as for login, with the exception that when they are prompted for their extension, they press the # key. It may be a good idea for us to review agents.conf. If we defined autologoff, then after the specified number of seconds of ringing, the agent will be automatically logged off. If we set ackcall to yes, then agents must press the # key to accept calls. If we created a wrapuptime (defined in milliseconds), then Asterisk will wait that many milliseconds before sending another call to the agent. These options can help us make our phone system as user friendly as we want it to be. Through the use of call queues, we can distribute our incoming calls efficiently and effectively. We have plenty of options, and can mix and match these three ways of joining users to queues. Call parking In many businesses across the United States, an operator can be heard announcing "John, you have a call on line 3. John, line 3." In Asterisk, we don't really have lines the way analog PBXs do. Our users are accustomed to not having to transfer calls, especially when they may not know exactly where John is. Asterisk uses a feature known as call parking to accomplish this same goal. Our users will transfer calls to a special extension, which will then tell them what extension to call in order to retrieve the call. Then our users can direct the intended recipient to dial that extension and connect to the call. In order to be able to use this feature, we must define our parking lot. This is done in the /etc/asterisk/parking.conf file. In this file, there are only a few options that we will need to configure. First, we must create the extension that people are to dial in order to park calls. This can be whatever extension is convenient for us. Then we will define a list of extensions on which to place parked calls. These extensions will be what users dial to retrieve a parked call. Next, we will define what context we want our parked calls to be in. Finally, we will define how many seconds a call remains parked before ringing back to the user who parked it. Here is an example: [general]parkext => 8100parkpos => 8101-8199context => parkedcallsparkingtime => 120 These settings would mean that we can park calls by dialing 8100, and the call will be placed in extensions 8101 through 8199, giving us the ability to have up to 99 parked calls at any given time. The calls will be in the context called parkedcalls, which means we should be careful to include it in any context where users should be able to park and retrieve calls. When our users transfer a call to extension 8100, they will hear Asterisk read out the extension that the call has been placed on. They can now make a note of it and notify the appropriate co-worker of the extension to reach the calling customer on. If the call is not picked up within the given parkingtime, then the call will ring back to the user who parked the call. By using call parking, we can help our users by providing a feature similar to that of previous generations of PBXs. This also allows users to collaborate and redirect callers to other users who are better equipped to handle our customers' needs. Direct Inward Dialing (DID) Suppose we work at a healthcare company with over 100 employees. We have two PRI lines coming in, and only three switchboard agents to handle incoming calls. As a healthcare company, we schedule many appointments, answer questions about prescriptions, and help patients with billing questions. These three agents are always busy. Now suppose the IT guy's wife calls in to ask if he wants sprouts or mash with his dinner. Do we want our switchboard agents to have to answer the call, find out who it is and what they want, and then transfer the call, or would we rather want the IT guy's wife to call her husband directly? This is where Direct Inward Dialing (DID) comes in handy. DID is a service provided by phone companies where they send an agreed-upon set of digits, depending on the number the customer dialed. For most phone companies, the sent digits will be the full ten-digit number (in the United States). But this can be as small as the last digit. All right, so the phone company is sending digits. What are we going to do with them? Imagine you have a PRI coming in to your office, and only ten phone numbers—a block from (850) 555-5550 to 5559. Your phone company has agreed to send you only the last digit dialed, which will be from 0 to 9, because you are guaranteed for this to be unique. Asterisk can route calls based on this DID information. If we have our PRI line's channels defined to go into a context called incoming, this context could look like: [incoming]s,1,Goto(default,s,1)i,1,Goto(default,s,1)t,1,Goto(default,s,1)0,1,Goto(default,1234,1)1,1,Goto(default,2345,1)2,1,Goto(default,3456,1)3,1,Goto(default,4567,1)4,1,Goto(default,5678,1)5,1,Goto(default,6789,1)6,1,Goto(default,7890,1)7,1,Goto(default,1111,1)8,1,Goto(default,1111,1)9,1,Goto(default,1111,1) There are a few things we should notice about this. First, we handled the error cases. What if a glitch at the phone company results in four digits being sent? We cannot allow a simple mistake on their end to interrupt our ability to receive phone calls. Secondly, we are using Goto statements. We've briefly discussed how they can be both good and bad. In this case, if a user moves from one extension to another by using Goto, we have to update it only in the default context. Finally, we are allowed to send multiple incoming DIDs to the same extension, if we so desire, as in the last three lines shown in the previous code. This might be useful if extension 1111 is the operator, and we do not yet have the number 7, 8, or 9 assigned to a user. Of course, in real life this is going to get much more complicated, as phone numbers will probably come in with the full ten digits. But the concept is the same—we can define extensions based upon information that the phone company sends when the call is established. By using DIDs, we can cut down on bottlenecks and give direct access to certain extensions. This tool of Asterisk helps make our phone system fast, efficient, and friendly to our users and customers.  
Read more
  • 0
  • 0
  • 3261

article-image-about-mongodb
Packt
27 Nov 2014
17 min read
Save for later

About MongoDB

Packt
27 Nov 2014
17 min read
In this article by Amol Nayak, the author of MongoDB Cookbook, describes the various features of MongoDB. (For more resources related to this topic, see here.) MongoDB is a document-oriented database and is the most popular and favorite NoSQL database. The rankings given at http://db-engines.com/en/ranking shows us that MongoDB is sitting on the fifth rank overall as of August 2014 and is the first NoSQL product in this list. It is currently being used in production by a huge list of companies in various domains handling terabytes of data efficiently. MongoDB is developed to scale horizontally and cope up with the increasing data volumes. It is very simple to use and get started with, backed by a good support from its company MongoDB and has a vast array open source and proprietary tools build around it to improve developer and administrator's productivity. In this article, we will cover the following recipes: Single node installation of MongoDB with options from the config file Viewing database stats Creating an index and viewing plans of queries Single node installation of MongoDB with options from the config file As we're aware that providing options from the command line does the work, but it starts getting awkward as soon as the number of options we provide increases. We have a nice and clean alternative to providing the startup options from a configuration file rather than as command-line arguments. Getting ready Well, assuming that we have downloaded the MongoDB binaries from the download site, extracted it, and have the bin directory of MongoDB in the operating system's path variable (this is not mandatory but it really becomes convenient after doing it), the binaries can be downloaded from http://www.mongodb.org/downloads after selecting your host operating system. How to do it… The /data/mongo/db directory for the database and /logs/ for the logs should be created and present on your filesystem, with the appropriate permissions to write to it. Let's take a look at the steps in detail: Create a config file, which can have any arbitrary name. In our case, let's say we create the file at /conf/mongo.conf. We will then edit the file and add the following lines of code to it: port = 27000 dbpath = /data/mongo/db logpath = /logs/mongo.log smallfiles = true Start the Mongo server using the following command: > mongod --config /config/mongo.conf How it works… The properties are specified as <property name> = <value>. For all those properties that don't have values, for example, the smallfiles option, the value given is a Boolean value, true. If you need to have a verbose output, you will add v=true (or multiple v's to make it more verbose) to our config file. If you already know what the command-line option is, it is pretty easy to guess the value of the property in the file. It is the same as the command-line option, with just the hyphen removed. Viewing database stats In this recipe, we will see how to get the statistics of a database. Getting ready To find the stats of the database, we need to have a server up and running, and a single node is what should be ok. The data on which we would be operating needs to be imported into the database. Once these steps are completed, we are all set to go ahead with this recipe. How to do it… We will be using the test database for the purpose of this recipe. It already has the postalCodes collection in it. Let's take a look at the steps in detail: Connect to the server using the Mongo shell by typing in the following command from the operating system terminal (it is assumed that the server is listening to port 27017): $ mongo On the shell, execute the following command and observe the output: > db.stats() Now, execute the following command, but this time with the scale parameter (observe the output): > db.stats(1024) { "db" : "test", "collections" : 3, "objects" : 39738, "avgObjSize" : 143.32699179626553, "dataSize" : 5562, "storageSize" : 16388, "numExtents" : 8, "indexes" : 2, "indexSize" : 2243, "fileSize" : 196608, "nsSizeMB" : 16, "dataFileVersion" : {    "major" : 4,    "minor" : 5 }, "ok" : 1 } How it works… Let us start by looking at the collections field. If you look carefully at the number and also execute the show collections command on the Mongo shell, you shall find one extra collection in the stats as compared to those by executing the command. The difference is for one collection, which is hidden, and its name is system.namespaces. You may execute db.system.namespaces.find() to view its contents. Getting back to the output of stats operation on the database, the objects field in the result has an interesting value too. If we find the count of documents in the postalCodes collection, we see that it is 39732. The count shown here is 39738, which means there are six more documents. These six documents come from the system.namespaces and system.indexes collection. Executing a count query on these two collections will confirm it. Note that the test database doesn't contain any other collection apart from postalCodes. The figures will change if the database contains more collections with documents in it. The scale parameter, which is a parameter to the stats function, divides the number of bytes with the given scale value. In this case, it is 1024, and hence, all the values will be in KB. Let's analyze the output: > db.stats(1024) { "db" : "test", "collections" : 3, "objects" : 39738, "avgObjSize" : 143.32699179626553, "dataSize" : 5562, "storageSize" : 16388, "numExtents" : 8, "indexes" : 2, "indexSize" : 2243, "fileSize" : 196608, "nsSizeMB" : 16, "dataFileVersion" : {    "major" : 4,    "minor" : 5 }, "ok" : 1 } The following table shows the meaning of the important fields: Field Description db This is the name of the database whose stats are being viewed. collections This is the total number of collections in the database. objects This is the count of documents across all collections in the database. If we find the stats of a collection by executing db.<collection>.stats(), we get the count of documents in the collection. This attribute is the sum of counts of all the collections in the database. avgObjectSize This is simply the size (in bytes) of all the objects in all the collections in the database, divided by the count of the documents across all the collections. This value is not affected by the scale provided even though this is a size field. dataSize This is the total size of the data held across all the collections in the database. This value is affected by the scale provided. storageSize This is the total amount of storage allocated to collections in this database for storing documents. This value is affected by the scale provided. numExtents This is the count of all the number of extents in the database across all the collections. This is basically the sum of numExtents in the collection stats for collections in this database. indexes This is the sum of number of indexes across all collections in the database. indexSize This is the size (in bytes) for all the indexes of all the collections in the database. This value is affected by the scale provided. fileSize This is simply the addition of the size of all the database files you should find on the filesystem for this database. The files will be named test.0, test.1, and so on for the test database. This value is affected by the scale provided. nsSizeMB This is the size of the file in MBs for the .ns file of the database. Another thing to note is the value of the avgObjectSize, and there is something weird in this value. Unlike this very field in the collection's stats, which is affected by the value of the scale provided. In database stats, this value is always in bytes, which is pretty confusing and one cannot really be sure why this is not scaled according to the provided scale. Creating an index and viewing plans of queries In this recipe, we will look at querying data, analyzing its performance by explaining the query plan, and then optimizing it by creating indexes. Getting ready For the creation of indexes, we need to have a server up and running. A simple single node is what we will need. The data with which we will be operating needs to be imported in the database. Once we have this prerequisite, we are good to go. How to do it… We will trying to write a query that will find all the zip codes in a given state. To do this, perform the following steps: Execute the following query to view the plan of a query: > db.postalCodes.find({state:'Maharashtra'}).explain() Take a note of the cursor, n, nscannedObjects, and millis fields in the result of the explain plan operation Let's execute the same query again, but this time, we will limit the results to only 100 results: > db.postalCodes.find({state:'Maharashtra'}).limit(100).explain() Again, take a note of the cursor, n, nscannedObjects, and millis fields in the result We will now create an index on the state and pincode fields as follows: > db.postalCodes.ensureIndex({state:1, pincode:1}) Execute the following query: > db.postalCodes.find({state:'Maharashtra'}).explain() Again, take a note of the cursor, n, nscannedObjects, millis, and indexOnly fields in the result Since we want only the pin codes, we will modify the query as follows and view its plan: > db.postalCodes.find({state:'Maharashtra'}, {pincode:1, _id:0}).explain() Take a note of the cursor, n, nscannedObjects, nscanned, millis, and indexOnly fields in the result. How it works… There is a lot to explain here. We will first discuss what we just did and how to analyze the stats. Next, we will discuss some points to be kept in mind for the index creation and some gotchas. Analysis of the plan Let's look at the first step and analyze the output we executed: > db.postalCodes.find({state:'Maharashtra'}).explain() The output on my machine is as follows (I am skipping the nonrelevant fields for now): {        "cursor" : "BasicCursor",          "n" : 6446,        "nscannedObjects" : 39732,        "nscanned" : 39732,          …        "millis" : 55, …       } The value of the cursor field in the result is BasicCursor, which means a full collection scan (all the documents are scanned one after another) has happened to search the matching documents in the entire collection. The value of n is 6446, which is the number of results that matched the query. The nscanned and nscannedobjects fields have values of 39,732, which is the number of documents in the collection that are scanned to retrieve the results. This is the also the total number of documents present in the collection, and all were scanned for the result. Finally, millis is the number of milliseconds taken to retrieve the result. Improving the query execution time So far, the query doesn't look too good in terms of performance, and there is great scope for improvement. To demonstrate how the limit applied to the query affects the query plan, we can find the query plan again without the index but with the limit clause: > db.postalCodes.find({state:'Maharashtra'}).limit(100).explain()   { "cursor" : "BasicCursor", …      "n" : 100,      "nscannedObjects" : 19951,      "nscanned" : 19951,        …      "millis" : 30,        … } The query plan this time around is interesting. Though we still haven't created an index, we saw an improvement in the time the query took for execution and the number of objects scanned to retrieve the results. This is due to the fact that Mongo does not scan the remaining documents once the number of documents specified in the limit function is reached. We can thus conclude that it is recommended that you use the limit function to limit your number of results, whereas the maximum number of documents accessed is known upfront. This might give better query performance. The word "might" is important, as in the absence of index, the collection might still be completely scanned if the number of matches is not met. Improvement using indexes Moving on, we will create a compound index on state and pincode. The order of the index is ascending in this case (as the value is 1) and is not significant unless we plan to execute a multikey sort. This is a deciding factor as to whether the result can be sorted using only the index or whether Mongo needs to sort it in memory later on, before we return the results. As far as the plan of the query is concerned, we can see that there is a significant improvement: {        "cursor" : "BtreeCursor state_1_pincode_1", …          "n" : 6446,        "nscannedObjects" : 6446,        "nscanned" : 6446, …        "indexOnly" : false, …        "millis" : 16, … } The cursor field now has the BtreeCursor state_1_pincode_1 value , which shows that the index is indeed used now. As expected, the number of results stays the same at 6446. The number of objects scanned in the index and documents scanned in the collection have now reduced to the same number of documents as in the result. This is because we now used an index that gave us the starting document from which we could scan, and then, only the required number of documents were scanned. This is similar to using the book's index to find a word or scanning the entire book to search for the word. The time, millis has come down too, as expected. Improvement using covered indexes This leaves us with one field, indexOnly, and we will see what this means. To know what this value is, we need to look briefly at how indexes operate. Indexes store a subset of fields of the original document in the collection. The fields present in the index are the same as those on which the index is created. The fields, however, are kept sorted in the index in an order specified during the creation of the index. Apart from the fields, there is an additional value stored in the index; this acts as a pointer to the original document in the collection. Thus, whenever the user executes a query, if the query contains fields on which an index is present, the index is consulted to get a set of matches. The pointer stored with the index entries that match the query is then used to make another IO operation to fetch the complete document from the collection; this document is then returned to the user. The value of indexOnly, which is false, indicates that the data requested by the user in the query is not entirely present in the index, but an additional IO operation is needed to retrieve the entire document from the collection that follows the pointer from the index. Had the value been present in the index itself, an additional operation to retrieve the document from the collection will not be necessary, and the data from the index will be returned. This is called covered index, and the value of indexOnly, in this case, will be true. In our case, we just need the pin codes, so why not use projection in our queries to retrieve just what we need? This will also make the index covered as the index entry that just has the state's name and pin code, and the required data can be served completely without retrieving the original document from the collection. The plan of the query in this case is interesting too. Executing the following query results in the following plan: db.postalCodes.find({state:'Maharashtra'}, {pincode:1, _id:0}).explain() {        "cursor" : "BtreeCursor state_1_pincode_1", …        "n" : 6446,        "nscannedObjects" : 0,        "nscanned" : 6446, … "indexOnly" : true, …            "millis" : 15, … } The values of the nscannedobjects and indexOnly fields are something to be observed. As expected, since the data we requested in the projection in the find query is pin code only, which can be served from the index alone, the value of indexOnly is true. In this case, we scanned 6,446 entries in the index, and thus, the nscanned value is 6446. We, however, didn't reach out to any document in the collection on the disk, as this query was covered by the index alone, and no additional IO was needed to retrieve the entire document. Hence, the value of nscannedobjects is 0. As this collection in our case is small, we do not see a significant difference in the execution time of the query. This will be more evident on larger collections. Making use of indexes is great and gives good performance. Making use of covered indexes gives even better performance. Another thing to remember is that wherever possible, try and use projection to retrieve only the number of fields we need. The _id field is retrieved every time by default, unless we plan to use it set _id:0 to not retrieve it if it is not part of the index. Executing a covered query is the most efficient way to query a collection. Some gotchas of index creations We will now see some pitfalls in index creation and some facts where the array field is used in the index. Some of the operators that do not use the index efficiently are the $where, $nin, and $exists operators. Whenever these operators are used in the query, one should bear in mind a possible performance bottleneck when the data size increases. Similarly, the $in operator must be preferred over the $or operator, as both can be more or less used to achieve the same result. As an exercise, try to find the pin codes in the state of Maharashtra and Gujarat from the postalCodes collection. Write two queries: one using the $or operator and the other using the $in operator. Explain the plan for both these queries. What happens when an array field is used in the index? Mongo creates an index entry for each element present in the array field of a document. So, if there are 10 elements in an array in a document, there will be 10 index entries, one for each element in the array. However, there is a constraint while creating indexes that contain array fields. When creating indexes using multiple fields, not more than one field can be of the array type. This is done to prevent the possible explosion in the number of indexes on adding even a single element to the array used in the index. If we think of it carefully, for each element in the array, an index entry is created. If multiple fields of type array were allowed to be part of an index, we would have a large number of entries in the index, which would be a product of the length of these array fields. For example, a document added with two array fields, each of length 10, will add 100 entries to the index, had it been allowed to create one index using these two array fields. This should be good enough for now to scratch the surfaces of plain vanilla index. Summary This article provides detailed recipes that describe how to use the different features of MongoDB. MongoDB is a document-oriented, leading NoSQL database, which offers linear scalability, thus making it a good contender for high-volume, high-performance systems across all business domains. It has an edge over the majority of NoSQL solutions for its ease of use, high performance, and rich features. In this article, we learned how to start single node installations of MongoDB with options from the config file. We also learned how to create an index from the shell and viewing plans of queries. Resources for Article: Further resources on this subject: Ruby with MongoDB for Web Development [Article] MongoDB data modeling [Article] Using Mongoid [Article]
Read more
  • 0
  • 0
  • 3259

article-image-organizing-your-balsamiq-files
Packt
09 Oct 2012
3 min read
Save for later

Organizing your Balsamiq files

Packt
09 Oct 2012
3 min read
There are two important things to note about organizing your files in Balsamiq: Keep all of your .bmml files together. The assets folder houses everything else, that is, artwork, logos, PDFs, PSDs, symbols, and so on, as shown in the following screenshot: Naming your files Naming your files in Balsamiq is very important. This is because Balsamiq does not automatically remember the order in which you organized your files after you closed them. Balsamiq will reopen them in the order in which they are sitting in a folder. There are, however, two ways you can gain greater control. Alphabetically You could alphabetize your files, although this could pose a problem as you add and delete files, requiring you to carefully name the new files so that they open in the same order as before. While it is a fine solution, the time it takes to ensure proper alphabetization does not seem worth the effort. Numbering The second, and more productive way, to name your files is to not name them at all, but instead to number them. For example, after naming a new .bmml file, add a number to the end of it in sequential order, for example, filename_1, filename_2, filename_3, and so on. Subpages, in turn, become filename_1a, filename_1b, filename_1c, and so on. Keep in mind, however, that if you add, delete, or modify numbered files, you may still have to modify the remaining page numbers accordingly. Nevertheless, I suspect you will find it to be easier than alphabetizing. Another way to number your files can be found on Balsamiq's website. The link to the exact page is a bit long. Go to http://www.balsamiq.com/ and do a search for Managing Projects in Mockups for Desktop. In the article, they recommend an alternate method of numbering your files by 10s, for example, filename_10, filename_20, filename_30, and so on. The idea being that as you add or remove pages, you can do so incrementally, rather than having to do a complete renumbering each time. In other words, you could add numbers between 11 and 19 and still be fine. Keep in mind that if you choose to use single digits, be sure to add a zero before the filename for consistency and to ensure proper file folder organization, for example, filename_05, filename_06, filename_07, and so on. How you name or number your files is completely up to you. These tips are simply recommendations to consider. The bottom line is to find a system for naming your files that works for you and to stick with it. You will be glad you did.
Read more
  • 0
  • 0
  • 3258

article-image-drupal-intranets-open-atrium-creating-dashboard
Packt
05 Jan 2011
7 min read
Save for later

Drupal Intranets with Open Atrium: Creating Dashboard

Packt
05 Jan 2011
7 min read
Drupal Intranets with Open Atrium Discover an intranet solution for your organization with Open Atrium Unlock the features of Open Atrium to set up an intranet to improve communication and workflow Explore the many features of Open Atrium and how you can utilize them in your intranet Learn how to support, maintain, and administer your intranet A how-to guide written for non-developers to learn how to set up and use Open Atrium   Main dashboard The main dashboard provides an interface for managing and monitoring our Open Atrium installation. This dashboard provides a central place to monitor what's going on across our departments. It will also be used as the central gateway for most of our administrative tasks. From this screen we can add groups, invite users, and customize group dashboards. Each individual who logs in also has the main dashboard and can quickly glance at the overall activity for their company. The dashboard is laid out initially by default in a two column layout. The left side of the screen contains the Main Content section and the right side of the screen contains a Sidebar. In a default installation of Open Atrium, there will be a welcome video in the Main Content area on the left. The first thing that you will notice when you log in is that there is a quick video that you can play on your main dashboard screen. This video provides a quick overview of Open Atrium for our users, and a review of the options you have for working with the dashboard. In the following screenshot, you will see the main dashboard and how the two separate content areas are divided, with a specific section marked that we will discuss later in the article: Each dashboard can be customized to either a two-column or split layout, as shown in the preceding screenshot, or a three-column layout. Under the Modifying Layout section of this article, we will cover how to change the overall layout. As you can see in the preceding image, the dashboard is divided into three distinct sections. There is the header area which includes the Navigation tabs for creating content, modifying settings, and searching the site. Under the header area, we have the main content and sidebar areas. These areas are made up of blocks of content from the site. These blocks can bring forward and include different items depending on how we customize our site. For example, in the left column we could choose to display Recent Activity and Blog Posts, while the right column could show Upcoming Events and a Calendar. Any of the features that we find throughout Open Atrium can be brought forward to a dashboard page. The beauty of this setup is that each group can customize their own. In the next section of this article, we will cover group dashboards in more detail. However, the same basic concepts will apply to all the dashboards. After our users are comfortable with using Open Atrium, we may decide that we no longer need to show the tutorial video on the main dashboard. This video can be easily removed by clicking on the Customizing the dashboard link just above the Recent Activity block or by clicking on the Customize dashboard link on the top right in the header section. Click on the customizing the dashboard link and we will see a dashboard widget on the screen. This will be the main interface for configuring layout and content on our dashboard. Now, hover over the video and on the top right you will see two icons. The first icon that looks like a plus sign (+) indicates that the content can be dragged. We can click on this icon when hovering over a section of content and move that content to another column or below another section of content on our dashboard. The X indicates that we can remove that item from our dashboard. Hovering over any piece of content when you are customizing the dashboard should reveal these two icons. The two icons are highlighted in the following screenshot with a square box drawn around them: To remove the welcome video, we click on the red X and then click on Save changes and the video tutorial will be removed from the dashboard. Group dashboard The group dashboard works the same as the main dashboard. The only difference is that the group dashboard exposes content for the individual departments or groups that are setup on our site. For example, a site could have a separate group for the Human Resources, Accounting, and Management departments. Each of these groups can create a group dashboard that can be customized by any of the administrators for a particular group. The following screenshot shows how the Human Resources department has customized their group dashboard:   In the preceding screenshot, we can see how the HR department customized their dashboard. In the left column they have added a Projects and a Blog section. The Projects section links to specific projects within the site, and the Blog section links to the detailed blog entries. There is also a customized block in the right column where the HR department has added the Upcoming events, a Mini calendar, and a Recent activity block. The Projects section is a block that is provided by the system and exposes content from the Case tracker or Todo sections of the HR website. The Upcoming events section is a customized block that highlights future events entered through the calendar feature. To demonstrate how each department can have a different dashboard, the following screenshot shows the dashboard for the Accounting department: The Accounting dashboard has been configured to show a custom block as the first item in the left column, and below that a listing of Upcoming events. In the right column, the Accounting administrator has added a block which brings forward the Latest cases of all the latest cases, exposing the most recent issues entered into the tracking system. It is also worth noting that the Accounting department has a completely different color scheme from the Human Resources department. The color scheme can be changed by clicking on Settings | Group Settings | Features. We can scroll down to the bottom of the screen and click on BACKGROUND to either enter a hexadecimal color for our main color or pick a color from the color wheel as displayed in the following screenshot: Spaces Spaces is a Drupal API module that allows sitewide configurable options to be overridden by individual spaces. The spaces API is included with our Open Atrium installation and provides the foundation for creating group and user configurable dashboards. Users can then customize their space and set settings that are only applied to their space. This shows the extreme power and flexibility of Open Atrium by allowing users to apply customizations without affecting any of the other areas of Open Atrium. Users can use the functionality provided by spaces to create an individualized home page. Group spaces Group spaces provide an area for each group or department to arrange content in a contextual manner that makes sense for each group. In the preceding examples, the content that is important to the accounting department is not necessarily important to the human resources department. Administrators of each department can take advantage of Open Atrium's complete flexibility to arrange content in a way that works for them. The URLs in the example that we have been looking at are listed as follows: Human Resources: http://acme.alphageekdev.com/hr. Accounting: http://acme.alphageekdev.com/acct Each URL is composed of the site URL, that is, http://acme.alphageekdev.com/ and then the short name that we provided for our group space, hr and acct. User spaces User spaces work in the same way that the group dashboard and spaces work. Each user of the system can customize their dashboard any way that they see appropriate. The following screenshot shows an example of the user's dashboard for the admin account: In the preceding screenshot, we have drawn a box around two areas. These two areas represent two different group spaces showing on the user's dashboard page. This shows how content can be brought forward to various dashboards to show only what is important to a particular user.
Read more
  • 0
  • 0
  • 3258

article-image-handling-selinux-aware-applications
Packt
19 Sep 2014
5 min read
Save for later

Handling SELinux-aware Applications

Packt
19 Sep 2014
5 min read
This article is written by Sven Vermeulen, the author of SELinux Cookbook. In this article, we will cover how to control D-Bus message flows. (For more resources related to this topic, see here.) Controlling D-Bus message flows D-Bus implementation on Linux is an example of an SELinux-aware application, acting as a user space object manager. Applications can register themselves on a bus and can send messages between applications through D-Bus. These messages can be controlled through the SELinux policy as well. Getting ready Before looking at the SELinux access controls related to message flows, it is important to focus on a D-Bus service and see how its authentication is done (and how messages are relayed in D-Bus) as this is reflected in the SELinux integration. Go to /etc/dbus-1/system.d/ (which hosts the configuration files for D-Bus services) and take a look at a configuration file. For instance, the service configuration file for dnsmasq looks like the following: <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> <busconfig> <policy user="root">    <allow own="uk.org.thekelleys.dnsmasq"/>    <allow send_destination="uk.org.thekelleys.dnsmasq"/> </policy> <policy context="default">    <deny own="uk.org.thekelleys.dnsmasq"/>    <deny send_destination="uk.org.thekelleys.dnsmasq"/> </policy> </busconfig> This configuration tells D-Bus that only the root Linux user is allowed to have a service own the uk.org.thekelleys.dnsmasq service and send messages to this service. Others (as managed through the default policy) are denied these operations. On a system with SELinux enabled, having root as the finest granularity doesn't cut it. So, let's look at how the SELinux policy can offer a fine-grained access control in D-Bus. How to do it… To control D-Bus message flows with SELinux, perform the following steps: Identify the domain of the application that will (or does) own the D-Bus service we are interested in. For the dnsmasq application, this would be dnsmasq_t: ~# ps -eZ | grep dnsmasq | awk '{print $1}' system_u:system_r:dnsmasq_t:s0-s0:c0.c1023 Identify the domain of the application that wants to send messages to the service. For instance, this could be the sysadm_t user domain. Allow the two domains to interact with each other through D-Bus messages as follows: gen_require(` class dbus send_msg; ') allow sysadm_t dnsmasq_t:dbus send_msg; allow dnsmasq_t sysadm_t:dbus send_msg; How it works… When an application connects to D-Bus, the SELinux label of its connection is used as the label to check when sending messages. As there is no transition for such connections, the label of the connection is the context of the process itself (the domain); hence, the selection of dnsmasq_t in the example. When D-Bus receives a request to send a message to a service, D-Bus will check the SELinux policy for the send_msg permission. It does so by passing on the information about the session (source and target context and the permission that is requested) to the SELinux subsystem, which computes whether access should be allowed or not. The access control itself, however, is not enforced by SELinux (it only gives feedback), but by D-Bus itself as governing the message flows is solely D-Bus' responsibility. This is also why, when developing D-Bus-related policies, both the class and permission need to be explicitly mentioned in the policy module. Without this, the development environment might error out, claiming that dbus is not a valid class. D-Bus checks the context of the client that is sending a message as well as the context of the connection of the service (which are both domain labels) and see if there is a send_msg permission allowed. As most communication is two-fold (sending a message and then receiving a reply), the permission is checked in both directions. After all, sending a reply is just sending a message (policy-wise) in the reverse direction. It is possible to verify this behavior with dbus-send if the rule is on a user domain. For instance, to look at the objects provided by the service, the D-Bus introspection can be invoked against the service: ~# dbus-send --system --dest=uk.org.thekelleys.dnsmasq --print-reply /uk/org/thekelleys/dnsmasq org.freedesktop.DBus.Introspectable.Introspect When SELinux does not have the proper send_msg allow rules in place, the following error will be logged by D-Bus in its service logs (but no AVC denial will show up as it isn't the SELinux subsystem that denies the access): Error org.freedesktop.DBus.Error.AccessDenied: An SELinux policy prevents this sender from sending this message to this recipient. 0 matched rules; type="method_call", sender=":1.17" (uid=0 pid=6738 comm="") interface="org.freedesktop.DBus.Introspectable" member="Introspect" error name="(unset)" requested_reply="0" destination="uk.org.thekelleys.dnsmasq" (uid=0 pid=6635 comm="") When the policy does allow the send_msg permission, the introspection returns an XML output showing the provided methods and interfaces for this service. There's more... The current D-Bus implementation is a pure user space implementation. Because more applications become dependent on D-Bus, work is being done to create a kernel-based D-Bus implementation called kdbus. The exact implementation details of this project are not finished yet, so it is unknown whether the SELinux access controls that are currently applicable to D-Bus will still be valid on kdbus. Summary In this article, we learned how to control D-Bus message flows. It also covers what happens when the policy has or doesn't have the send_msg permission in place. Resources for Article: Further resources on this subject: An Introduction to the Terminal [Article] Wireless and Mobile Hacks [Article] Baking Bits with Yocto Project [Article]
Read more
  • 0
  • 0
  • 3258
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at $19.99/month. Cancel anytime
article-image-geolocating-photos-map
Packt
25 Mar 2015
7 min read
Save for later

Geolocating photos on the map

Packt
25 Mar 2015
7 min read
In this article by Joel Lawhead, author of the book, QGIS Python Programming Cookbook uses the tags to create locations on a map for some photos and provide links to open them. (For more resources related to this topic, see here.) Getting ready You will need to download some sample geotagged photos from https://github.com/GeospatialPython/qgis/blob/gh-pages/photos.zip?raw=true and place them in a directory named photos in your qgis_data directory. How to do it... QGIS requires the Python Imaging Library (PIL), which should already be included with your installation. PIL can parse EXIF tags. We will gather the filenames of the photos, parse the location information, convert it to decimal degrees, create the point vector layer, add the photo locations, and add an action link to the attributes. To do this, we need to perform the following steps: In the QGIS Python Console, import the libraries that we'll need, including k for parsing image data and the glob module for doing wildcard file searches: import globimport Imagefrom ExifTags import TAGS Next, we'll create a function that can parse the header data: def exif(img):   exif_data = {}   try:         i = Image.open(img)       tags = i._getexif()       for tag, value in tags.items():         decoded = TAGS.get(tag, tag)           exif_data[decoded] = value   except:       passreturn exif_data Now, we'll create a function that can convert degrees-minute-seconds to decimal degrees, which is how coordinates are stored in JPEG images: def dms2dd(d, m, s, i):   sec = float((m * 60) + s)   dec = float(sec / 3600)   deg = float(d + dec)   if i.upper() == 'W':       deg = deg * -1   elif i.upper() == 'S':       deg = deg * -1   return float(deg) Next, we'll define a function to parse the location data from the header data: def gps(exif):   lat = None   lon = None   if exif['GPSInfo']:             # Lat       coords = exif['GPSInfo']       i = coords[1]       d = coords[2][0][0]       m = coords[2][1][0]       s = coords[2][2][0]       lat = dms2dd(d, m ,s, i)       # Lon       i = coords[3]       d = coords[4][0][0]       m = coords[4][1][0]       s = coords[4][2][0]       lon = dms2dd(d, m ,s, i)return lat, lon Next, we'll loop through the photos directory, get the filenames, parse the location information, and build a simple dictionary to store the information, as follows: photos = {}photo_dir = "/Users/joellawhead/qgis_data/photos/"files = glob.glob(photo_dir + "*.jpg")for f in files:   e = exif(f)   lat, lon = gps(e) photos[f] = [lon, lat] Now, we'll set up the vector layer for editing: lyr_info = "Point?crs=epsg:4326&field=photo:string(75)"vectorLyr = QgsVectorLayer(lyr_info, "Geotagged Photos" , "memory")vpr = vectorLyr.dataProvider() We'll add the photo details to the vector layer: features = []for pth, p in photos.items():   lon, lat = p   pnt = QgsGeometry.fromPoint(QgsPoint(lon,lat))   f = QgsFeature()   f.setGeometry(pnt)   f.setAttributes([pth])   features.append(f)vpr.addFeatures(features)vectorLyr.updateExtents() Now, we can add the layer to the map and make the active layer: QgsMapLayerRegistry.instance().addMapLayer(vectorLyr)iface.setActiveLayer(vectorLyr)activeLyr = iface.activeLayer() Finally, we'll add an action that allows you to click on it and open the photo: actions = activeLyr.actions()actions.addAction(QgsAction.OpenUrl, "Photos", '[% "photo" %]') How it works... Using the included PIL EXIF parser, getting location information and adding it to a vector layer is relatively straightforward. This action is a default option for opening a URL. However, you can also use Python expressions as actions to perform a variety of tasks. The following screenshot shows an example of the data visualization and photo popup: There's more... Another plugin called Photo2Shape is available, but it requires you to install an external EXIF tag parser. Image change detection Change detection allows you to automatically highlight the differences between two images in the same area if they are properly orthorectified. We'll do a simple difference change detection on two images, which are several years apart, to see the differences in urban development and the natural environment. Getting ready You can download the two images from https://github.com/GeospatialPython/qgis/blob/gh-pages/change-detection.zip?raw=true and put them in a directory named change-detection in the rasters directory of your qgis_data directory. Note that the file is 55 megabytes, so it may take several minutes to download. How to do it... We'll use the QGIS raster calculator to subtract the images in order to get the difference, which will highlight significant changes. We'll also add a color ramp shader to the output in order to visualize the changes. To do this, we need to perform the following steps: First, we need to import the libraries that we need in to the QGIS console: from PyQt4.QtGui import *from PyQt4.QtCore import *from qgis.analysis import * Now, we'll set up the path names and raster names for our images: before = "/Users/joellawhead/qgis_data/rasters/change-detection/before.tif"|after = "/Users/joellawhead/qgis_data/rasters/change-detection/after.tif"beforeName = "Before"afterName = "After" Next, we'll establish our images as raster layers: beforeRaster = QgsRasterLayer(before, beforeName)afterRaster = QgsRasterLayer(after, afterName) Then, we can build the calculator entries: beforeEntry = QgsRasterCalculatorEntry()afterEntry = QgsRasterCalculatorEntry()beforeEntry.raster = beforeRasterafterEntry.raster = afterRasterbeforeEntry.bandNumber = 1afterEntry.bandNumber = 2beforeEntry.ref = beforeName + "@1"afterEntry.ref = afterName + "@2"entries = [afterEntry, beforeEntry] Now, we'll set up the simple expression that does the math for remote sensing: exp = "%s - %s" % (afterEntry.ref, beforeEntry.ref) Then, we can set up the output file path, the raster extent, and pixel width and height: output = "/Users/joellawhead/qgis_data/rasters/change-detection/change.tif"e = beforeRaster.extent()w = beforeRaster.width()h = beforeRaster.height() Now, we perform the calculation: change = QgsRasterCalculator(exp, output, "GTiff", e, w, h, entries)change.processCalculation() Finally, we'll load the output as a layer, create the color ramp shader, apply it to the layer, and add it to the map, as shown here: lyr = QgsRasterLayer(output, "Change")algorithm = QgsContrastEnhancement.StretchToMinimumMaximumlimits = QgsRaster.ContrastEnhancementMinMaxlyr.setContrastEnhancement(algorithm, limits)s = QgsRasterShader()c = QgsColorRampShader()c.setColorRampType(QgsColorRampShader.INTERPOLATED)i = []qri = QgsColorRampShader.ColorRampItemi.append(qri(0, QColor(0,0,0,0), 'NODATA'))i.append(qri(-101, QColor(123,50,148,255), 'Significant Itensity Decrease'))i.append(qri(-42.2395, QColor(194,165,207,255), 'Minor Itensity Decrease'))i.append(qri(16.649, QColor(247,247,247,0), 'No Change'))i.append(qri(75.5375, QColor(166,219,160,255), 'Minor Itensity Increase'))i.append(qri(135, QColor(0,136,55,255), 'Significant Itensity Increase'))c.setColorRampItemList(i)s.setRasterShaderFunction(c)ps = QgsSingleBandPseudoColorRenderer(lyr.dataProvider(), 1, s)lyr.setRenderer(ps)QgsMapLayerRegistry.instance().addMapLayer(lyr) How it works... If a building is added in the new image, it will be brighter than its surroundings. If a building is removed, the new image will be darker in that area. The same holds true for vegetation, to some extent. Summary The concept is simple. We subtract the older image data from the new image data. Concentrating on urban areas tends to be highly reflective and results in higher image pixel values. Resources for Article: Further resources on this subject: Prototyping Arduino Projects using Python [article] Python functions – Avoid repeating code [article] Pentesting Using Python [article]
Read more
  • 0
  • 0
  • 3254

article-image-documentation-phpdocumentor-part-1
Packt
31 Mar 2010
11 min read
Save for later

Documentation with phpDocumentor: Part 1

Packt
31 Mar 2010
11 min read
Code-level documentation The documentation we will be creating describes the interface of the code more than minute details of the actual implementation. For example, you might document an API that you have developed for the outside world to interact with some insanely important project on which you are working. Having an API is great, but for other developers to quickly get an overview of the capabilities of the API and being able to crank out working code within a short amount of time is even better. If you are following the proper conventions while writing the code, all you would have to do is run a utility to extract and format the documentation from the code. Even if you're not inviting the whole world to interact with your software, developers within your own team will benefit from documentation describing some core classes that are being used throughout the project. Just imagine reading your co-worker's code and coming across some undecipherable object instance or method call. Wouldn't it be great to simply pull up the API documentation for that object and read about its uses, properties, and methods? Furthermore, it would be really convenient if the documentation for the whole project were assembled and logically organized in one location. That way, a developer cannot only learn about a specific class, but also about its relationships with other classes. In a way, it would enable the programmer to form a high-level picture of how the different pieces fit together. Another reason to consider code-level documentation is that source code is easily accessible due to PHP being a scripting language. Unless they choose to open source their code, compiled languages have a much easier time hiding their code. If you ever plan on making your project available for others to download and run on their own server, you are unwittingly inviting a potential critic or collaborator. Since it is rather hard (but not impossible) to hide the source code from a user that can download your project, there is the potential for people to start looking at and changing your code. Generally speaking, that is a good thing because they might be improving the quality and usefulness of the project and hopefully they will be contributing their improvements back to the user community. In such a case, you will be glad that you stuck to a coding standard and added comments throughout the code. It will make understanding your code much easier and anybody reading the code will come away with the impression that you are indeed a professional. Great, you say, how do I make sure I always generate such useful documentation when I program? The answer is simple. You need to invest a little time learning the right tool(s). That's the easy part for someone in the technology field where skill sets are being expanded every couple of years anyway. The hard part is to consistently apply that knowledge. Like much else in this book, it is a matter of training yourself to have good habits. Writing API level documentation at the same time as implementing a class or method should become second nature as much as following a coding standard or properly testing your code. Luckily, there are some tools that can take most of the tedium out of documenting your code. Foremost, modern IDEs (Integrated Development Environments) are very good at extracting some of the needed information automatically. Templates can help you generate documentation tags rather rapidly. Levels of detail As you create your documentation, you have to decide how detailed you want to get. I have seen projects where easily half the source code consisted of comments and documentation that produced fantastic developer and end-user documentation. However, that may not be necessary or appropriate for your project. My suggestion is to figure out what level of effort you can reasonably expect of yourself in relation to what would be appropriate for your target audience. After all, it is unlikely that you will start documenting every other line of code if you are not used to adding any documentation at all. On one hand, if your audience is relatively small and sophisticated, you might get away with less documentation. On the other hand, if you are documenting the web services API for a major online service as you are coding it, you probably want to be as precise and explicit as possible. Adding plenty of examples and tutorials might enable even novice developers to start using your API quickly. In that case, your employer's success in the market place is directly tied to the quality and accessibility of the documentation. In this case, the documentation is very much part of the product rather than an afterthought or merely an add-on. On one end of the spectrum, you can have documentation that pertains to the project as a whole, such as a "README" file. At the next level down, you might have a doc section at the beginning of each file. That way, you can cover the functionality of the file or class without going into too much detail. Introducing phpDocumentor phpDocumentor is an Open Source project that has established itself as the dominanot tool for documenting PHP code. Although there are other solutions, phpDocumentor is by far the one you are most likely to encounter in your work–and for good reason. Taking a clue from similar documentation tools that came before it, such as JavaDoc, phpDocumentor offers many features in terms of user interface, formatting, and so on. PhpDocumentor provides you with a large library of tags and other markup, which you can use to embed comments, documentation, and tutorials in your source code. The phpDoc markup is viewed as comments by PHP when it executes your source file and therefore doesn't interfere with the code's functionality. However, running the phpDocumentor command line executable or using the web-based interface, you can process all your source files, extract the phpDoc related content, and compile it into functional documentation. There is no need to look through the source files because phpDocumentor assembles the documentation into nicely looking HTML pages, text files, PDFs, or CHMs. Although phpDocumentor supports procedural programming and PHP4, the focus in this article will be on using it to document applications developed with object-oriented design in mind. Specifically, we will be looking at how to properly document interfaces, classes, properties, and methods. For details on how to document some of the PHP4 elements that don't typically occur in PHP5's object-oriented implementation, please consult the phpDocumentor online manual: http://manual.phpdoc.org/ Installing phpDocumentor There are two ways of installing phpDocumentor. The preferred way is to use the PEAR repository. Typing pear install PhpDocumentor from the command line will take care of downloading, extracting, and installing phpDocumentor for you. The pear utility is typically included in any recent standard distribution of PHP. However, if for some reason you need to install it first, you can download it from the PEAR site: http://pear.php.net/ Before we proceed with the installation, there is one important setting to consider. Traditionally, phpDocumentor has been run from the command line, however, more recent versions come with a rather functional web-based interface. If you want pear to install the web UI into a sub-directory of your web server's document root directory, you will first have to set pear's data_dir variable to the absolute path to that directory. In my case, I created a local site from which I can access various applications installed by pear. That directory is /Users/dirk/Sites/phpdoc. From the terminal, you would see the following if you tell pear where to install the web portion and proceed to install phpDocumentor. As part of the installation, the pear utility created a directory for phpDocumentor's web interface. Here is the listing of the contents of that directory: The other option for installing phpDocumentor is to download an archive from the project's SourceForge.net space. After that, it is just a matter of extracting the archive and making sure that the main phpdoc executable is in your path so that you can launch it from anywhere without having to type the absolute path. You will also have to manually move the corresponding directory to your server's document root directory to take advantage of the web-based interface. DocBlocks Let's start by taking a look at the syntax and usage of phpDocumentor.The basic unit of phpDoc documentation is a DocBlock. All DocBocks take the following format: /** * Short description * * Long description that can span as many lines as you wish. * You can add as much detail information and examples in this * section as you deem appropriate. You can even <i>markup</i> * this content or use inline tags like this: * {@tutorial Project/AboutInlineTags.proc} * * @tag1 * @tag2 value2 more text * ... more tags ... */ A DocBlock is the basic container of phpDocumentor markup within PHP source code. It can contain three different element groups: short description, long description, and tags–all of which are optional. The first line of a DocBlock has only three characters, namely "/**". Similarly, the last line will only have these three characters: " */ ". All lines in between will start with " * ". Short and long descriptions An empty line or a period at the end of the line terminates short descriptions. In contrast, long descriptions can go on for as many lines as necessary. Both types of descriptions allow certain markup to be used: <b>, <br>, <code>, <i>, <kbd>, <li>, <ol>, <p>, <pre>, <samp>, <ul>, <var>. The effect of these markup tags is borrowed directly from HTML. Depending on the output converter being used, each tag can be rendered in differe nt ways. Tags Tags are keywords known to phpDocumentor. Each tag can be followed by a number of optional arguments, such as data type, description, or URL. For phpDocumentor to recognize a tag, it has to be preceded by the @ character. Some examples of common tags are: /** * @package ForeignLanguageParser * @author Dirk Merkel dirk@waferthin.com * @link http://www.waferthin.com Check out my site */class Translate{} In addition to the above "standard" tags, phpDocumentor recognizes "inline" tags, which adhere to the same syntax, with the only notable difference that they are enclosed by curly brackets. Inline tags occur inline with short and long descriptions like this: /** * There is not enough space here to explain the value and usefulness * of this class, but luckily there is an extensive tutorial available * for you: {@tutorial ForeignLanguageParser/Tran slate.cls} */ DocBlock templates It often happens that the same tags apply to multiple successive elements. For example, you might group all private property declarations at the beginning of a class. In that case, it would be quite repetitive to list the same, or nearly the same DocBlocks, over and over again. Luckily, we can take advantage of DocBlock templates, which allow us to define DocBlock sections that will be added to the DocBlock of any element between a designated start and end point. DocBlock templates look just like regular DocBlocks with the difference that the first line consists of /**#@+ instead of /**. The tags in the template will be added to all subsequent DocBlocks until phpDocumenter encounters the ending letter sequence /**#@-*/. The following two code fragments will produce the same documentation. First, here is the version containing only standard DocBlocks: <?phpclass WisdomDispenser{ /** * @access protected * @var string */ private $firstSaying = 'Obey the golden rule.'; /** * @access protected * @var string */ private $secondSaying = 'Get in or get out.'; /** * @access protected * @var string * @author Albert Einstein <masterof@relativity.org> */ private $thirdSaying = 'Everything is relative';}?> And here is the fragment that will produce the same documentation using a more concise notation by taking advantage of DocBlock templates: <?phpclass WisdomDispenser{ /**#@+ * @access protected * @var string */ private $firstSaying = 'Obey the golden rule.'; private $secondSaying = 'Get in or get out.'; /** * @author Albert Einstein <masterof@relativity.org> */ private $thirdSaying = 'Everything is relative'; /**#@-*/}?>
Read more
  • 0
  • 0
  • 3252

article-image-red5-video-demand-flash-server
Packt
04 Jun 2010
6 min read
Save for later

Red5: A video-on-demand Flash Server

Packt
04 Jun 2010
6 min read
Plone does not provide a responsive user experience out of the box. This is not because the system is slow, but because it simply does (too) much. It does a lot of security checks and workflow operations, handles the content rules, does content validation, and so on. Still, there are some high-traffic sites running with the popular Content Management System. How do they manage? "All Plone integrators are caching experts." This saying is commonly heard and read in the Plone community. And it is true. If we want a fast and responsive system, we have to use caching and load-balancing applications to spread the load. The article discusses a practical example. We will set up a protected video-on-demand solution with Plone and a Red5 server. We will see how to integrate it with Plone for an effective and secure video-streaming solution. The Red5 server is an open source Flash server. It is written in Java and is very extensible via plugins. There are plugins for transcoding, different kinds of streaming, and several other manipulations we might want to do with video or audio content. What we want to investigate here is how to integrate video streams protected by Plone permissions. (For more resources on Plone, see here.) Requirements for setting up a Red5 server The requirement for running a Red5 Flash server is Java 6. We can check the Java version by running this: $ java -versionjava version "1.6.0_17"Java(TM) SE Runtime Environment (build 1.6.0_17-b04-248-9M3125)Java HotSpot(TM) 64-Bit Server VM (build 14.3-b01-101, mixed mode) The version needs to be 1.6 at least. The earlier versions of the Red5 server run with 1.5, but the plugin for protecting the media files needs Java 6. To get Java 6, if we do not have it already, we can download it from the Sun home page. There are packages available for Windows and Linux. Some Linux distributions have different implementations of Java because of licensing issues. You may check the corresponding documentation if this is the case for you. Mac OS X ships with its own Java bundled. To set the Java version to 1.6 on Mac OS X, we need to do the following: $ cd /System/Library/Frameworks/JavaVM.framework/Versions$ rm Current*$ ln -s 1.6 Current$ ln -s 1.6 CurrentJDK After doing so, we should double-check the Java version with the command shown before. The Red5 server is available as a package for various operating systems. In the next section, we will see how we can integrate a Red5 server into a Plone buildout. A Red5 buildout Red5 can be downloaded in several different ways. As it is open source, even the sources are available as a tarball from the product home page. For the buildout, we use the bundle of ready compiled Java libraries. This bundle comes with everything needed to run a standalone Red5 server. There are startup scripts provided for Windows and Bash (usable with Linux and Mac OS X). Let's see how to configure our buildout. The buildout needs the usual common elements for a Plone 3.3.3 installation. Apart from the application and the instance, the Red5-specific parts are also present: a fss storage part and a part for setting up the supervisor. [buildout]newest = falseparts =zope2instancefssred5red5-webappred5-protectedVODsupervisorextends =http://dist.plone.org/release/3.3.3/versions.cfgversions = versionsfind-links =http://dist.plone.org/release/3.3.3http://dist.plone.org/thirdpartyhttp://pypi.python.org/simple/ There is nothing special in the zope2 application part. [zope2]recipe = plone.recipe.zope2installfake-zope-eggs = trueurl = ${versions:zope2-url} On the Plone side, we need—despite of the fss eggs—a package called unimr.red5.protectedvod. This package with the rather complicated name creates rather complicated one-time URLs for the communication with Red5. [instance]recipe = plone.recipe.zope2instancezope2-location = ${zope2:location}user = admin:adminhttp-address = 8080eggs =Ploneunimr.red5.protectedvodiw.fsszcml =unimr.red5.protectedvodiw.fssiw.fss-meta First, we need to configure FileSystemStorage.FileSystemStorage is used for sharing the videos between Plone and Red5. The videos are uploaded via the Plone UI and they are put on the filesystem. The storage strategy needs to be either site1 or site2. These two strategies store the binary data with its original filename and file extension. The extension is needed for the Red5 server to recognize the file. [fss]recipe = iw.recipe.fsszope-instances =${instance:location}storages =global /site /site site2 The red5 part downloads and extracts the Red5 application. We have to envision that everything is placed into the parts directory. This includes configurations, plugins, logs, and even content. We need to be extra careful with changing the recipe in the buildout if running in production mode. The content we share with Plone is symlinked, so this is not a problem. For the logs, we might change the position to outside the parts directory and symlink them back. [red5]recipe = hexagonit.recipe.downloadurl = http://www.red5.org/downloads/0_8/red5-0.8.0.tar.gz The next part adds our custom application, which handles the temporary links used for protection, to the Red5 application. The plugin is shipped together with the unimr.red5.protectedvod egg we use on the Plone side. It is easier to get it from the Subversion repository directly. [red5-webapp]recipe = infrae.subversionurls = http://svn.plone.org/svn/collective/unimr.red5.protectedvod/trunk/unimr/red5/protectedvod/red5-webapp red5-webapp The red5-protectedVOD part configures the protectedVOD plugin. Basically, the WAR archive we checked out in the previous step is extracted. If the location of the fss storage does not exist already, it is symlinked into the streams directory of the plugin. The streams directory is the usual place for media files for Red5. [red5-protectedVOD]recipe = iw.recipe.cmdon_install = trueon_update = falsecmds =mkdir -p ${red5:location}/webapps/protectedVODcd ${red5:location}/webapps/protectedVODjar xvf ${red5-webapp:location}/red5-webapp/protectedVOD_0.1-red5_0.8-java6.warcd streamsif [ ! -L ${red5:location}/webapps/protectedVOD/streams/fss_storage_site ];then ln -s ${buildout:directory}/var/fss_storage_site .;fi The commands used above are Unix/Linux centric. Until Vista/ Server 2008, Windows didn't understand symbolic links. That's why the whole idea of the recipe doesn't work. The recipe might work with Windows Vista, Windows Server 2008, or Windows 7; but the commands look different Finally, we add the Red5 server to our supervisor configuration. We need to set the RED5_HOME environment variable, so that the startup script can find the necessary libraries of Red5. [supervisor]recipe = collective.recipe.supervisorprograms =30 instance2 ${instance2:location}/bin/runzope ${instance2:location}true40 red5 env [RED5_HOME=${red5:location} ${red5:location}/red5.sh]${red5:location} true After running the buildout, we can start the supervisor by issuing the following command: bin/supervisord The supervisor will take care of running all the subprocesses. To find out more on the supervisor, we may visit its website. To check if everything worked, we can request a status report by issuing this: bin/supervisorctl statusinstance RUNNING pid 2176, uptime 3:00:23red5 RUNNING pid 7563, uptime 0:51:25
Read more
  • 0
  • 0
  • 3252

article-image-building-jsfejb3-applications
Packt
22 Oct 2009
15 min read
Save for later

Building JSF/EJB3 Applications

Packt
22 Oct 2009
15 min read
Building JSF/EJB3 Applications This practical article shows you how to create a simple data-driven application using JSF and EJB3 technologies. The article also shows you how to effectively use NetBeans IDE when building enterprise applications. What We Are Going to Build The sample application we are building throughout the article is very straightforward. It offers just a few pages. When you click the Ask us a question link on the welcomeJSF.jsp page, you will be taken to the following page, on which you can submit a question:     Once you’re done with your question, you click the Submit button. As a result, the application persist your question along with your email in the database. The next page will look like this:     The web tier of the application is build using the JavaServer Faces technology, while EJB is used to implement the database-related code. Software You Need to Follow the Article Exercise To build the sample discussed here, you will need the following software components installed on your computer: Java Standard Development Kit (JDK) 5.0 or higher Sun Java System Application Server Platform Edition 9 MySQL NetBeans IDE 5.5 Setting Up the Database The first step in building our application is to set up the database to interact with. In fact, you could choose any database you like to be the application’s backend database. For the purpose of this article, though, we will discuss how to use MySQL. To keep things simple, let’s create a questions table that contains just three columns, outlined in the following table: Column Type Description trackno INTEGER AUTO_INCREMENT PRIMARY KEY Stores a track number generated automatically when a row is inserted. user_email VARCHAR(50) NOT NULL   question VARCHAR(2000) NOT NULL   Of course, a real-world questions table would contain a few more columns, for example, dateOfSubmission containing the date and time of submitting the question. To create the questions table, you first have to create a database and grant the required privileges to the user with which you are going to connect to that database. For example, you might create database my_db and user usr identified by password pswd. To do this, you should issue the following SQL commands from MySQL Command Line Client:   CREATE DATABASE my_db; GRANT CREATE, DROP, SELECT, INSERT, UPDATE, DELETE ON my_db.* TO 'usr'@'localhost' IDENTIFIED BY 'pswd'; In order to use the newly created database for subsequent statements, you should issue the following statement:   USE my_db   Finally, create the questions table in the database as follows:   CREATE TABLE questions(      trackno INTEGER AUTO_INCREMENT PRIMARY KEY,      user_email VARCHAR(50) NOT NULL,      question  VARCHAR(2000) NOT NULL ) ENGINE = InnoDB;     Once you’re done, you have the database with the questions table required to store incoming users’ questions. Setting Up a Data Source for Your MySQL Database Since the application we are going to build will interact with MySQL, you need to have installed an appropriate MySQL driver on your application server. For example, you might want to install MySQL Connector/J, which is the official JDBC driver for MySQL. You can pick up this software from the "downloads" page of the MySQL AB website at http://mysql.org/downloads/. Install the driver on your GlassFish application server as follows: Unpack the downloaded archive containing the driver to any directory on your machine Add mysql-connector-java-xxx-bin.jar to the CLASSPATH environment variable Make sure that your GlassFish application server is up and running Launch the Application Server Admin Console by pointing your browser at http://localhost:4848/ Within the Common Tasks frame, find and double-click the ResourcesJDBCNew Connection Pool node On the New Connection Pool page, click the New… button The first step of the New Connection Pool master, set the fields as shown in the following table: Setting Value Name jdbc/mysqlPool Resource type javax.sql.DataSource Database Vendor mysql   Click Next to move on to the second page of the master On the second page of New Connection Pool, set the properties to reflect your database settings, like that shown in the following table: Name Value databaseName my_db serverName localhost port 3306 user usr password pswd   Once you are done with setting the properties, click Finish. The newly created jdbc/mysqlPool connection pool should appear on the list. To check it, you should click its link to open it in a window, and then click the Ping button. If everything is okay, you should see a message telling you Ping succeeded Creating the Project The next step is to create an application project with NetBeans. To do this, follow the steps below: Choose File/New project and then choose the EnterpriseEnterprise Application template for the project. Click Next On the Name and Location page of the master, specify the name for the project: JSF_EJB_App. Also make sure that Create EJB Module and Create Web Application Module are checked. And click Finish As a result, NetBeans generates a new enterprise application in a standard project, containing actually two projects: an EJB module project and Web application project. In this particular example, you will use the first project for EJBs and the second one for JSF pages. Creating Entity Beans and Persistent Unit You create entity beans and the persistent unit in the EJB module project—in this example this is the JSF_EJB_App-ejb project. In fact, the sample discussed here will contain the only entity bean: Question. You might automatically generate it and then edit as needed. To generate it with NetBeans, follow the steps below: Make sure that your Sun Java System Application Server is up and running In the Project window, right click JSF_EJB_App-ejb project, and then choose New/Entity Classes From Database. As a result, you’ll be prompted to connect to your Sun Java System Application Server. Do it by entering appropriate credentials. In the New Entity Classes from Database window, select jdbc/mysqlPool from the Data Source combobox. If you recall from the Setting up a Data Source for your MySQL database section discussed earlier in this article, jdbc/mysqlPool is a JDBC connection pool created on your application server In the Connect dialog appeared, you’ll be prompted to connect to your MySQL database. Enter password pswd, set the Remember password during this session checkbox, and then click OK In the Available Tables listbox, choose questions, and click Add button to move it to the Selected Tables listbox. After that, click Next On the next page of the New Entity Classes from Database master, fill up the Package field. For example, you might choose the following name: myappejb.entities. And change the class name from Questions to Question in the Class Names box. Next, click the Create Persistent Unit button In the Create Persistent Unit window, just click the Create button, leaving default values of the fields In the New Entity Classes from Database dialog, click Finish As a result, NetBeans will generate the Question entity class, which you should edit so that the resultant class looks like the following:   package myappejb.entities; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "questions") public class Question implements Serializable { @Id @Column(name = "trackno") private Integer trackno; @Column(name = "user_email", nullable = false) private String userEmail; @Column(name = "question", nullable = false) private String question; public Question() { } public Integer getTrackno() { return this.trackno; } public void setTrackno(Integer trackno) { this.trackno = trackno; } public String getUserEmail() { return this.userEmail; } public void setUserEmail(String userEmail) { this.userEmail = userEmail; } public String getQuestion() { return this.question; } public void setQuestion(String question) { this.question = question; } }     Once you’re done, make sure to save all the changes made by choosing File/Save All. Having the above code in hand, you might of course do without first generating the Question entity from the database, but simply create an empty Java file in the myappejb.entities package, and then insert the above code there. Then you could separately create the persistent unit. However, the idea behind building the Question entity with the master here is to show how you can quickly get a required piece of code to be then edited as needed, rather than creating it from scratch. Creating Session Beans To finish with the JSF_EJB_App-ejb project, let’s proceed to creating the session bean that will be used by the web tier. In particular, you need to create the QuestionSessionBean session bean that will be responsible for persisting the data a user enters on the askquestion page. To generate the bean’s frame with a master, follow the steps below: In the Project window, right click JSF_EJB_App-ejb project, and then choose New/Session Bean In the New Session Bean window, enter EJB name: QuestionSessionBean. Then specify the package: myappejb.ejb. Make sure that the Session Type is set to Stateless and Create Interface is set to Remote. Click Finish As a result, NetBeans should generate two Java files: QuestionSessionBean.java and QuestionSessionRemote.java. You should modify QuestionSessionBean.java so that it contains the following code:   package myappejb.ejb; import javax.annotation.Resource; import javax.ejb.Stateless; import javax.ejb.TransactionManagement; import javax.ejb.TransactionManagementType; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.PersistenceUnit; import javax.transaction.UserTransaction; import myappejb.entities.Question; @Stateless <b>@TransactionManagement(TransactionManagementType.BEAN)</b> public class QuestionSessionBean implements myappejb.ejb.QuestionSessionRemote { /** Creates a new instance of QuestionSessionBean */ public QuestionSessionBean() { } @Resource private UserTransaction utx; @PersistenceUnit(unitName = "JSF_EJB_App-ejbPU") private EntityManagerFactory emf; private EntityManager getEntityManager() { return emf.createEntityManager(); } public void save(Question question) throws Exception { EntityManager em = getEntityManager(); try { utx.begin(); em.joinTransaction(); em.persist(question); utx.commit(); } catch (Exception ex) { try { utx.rollback(); throw new Exception(ex.getLocalizedMessage()); } catch (Exception e) { throw new Exception(e.getLocalizedMessage()); } } finally { em.close(); } } }   Next, modify the QuestionSessionRemote.java so that it looks like this:   package myappejb.ejb; import javax.ejb.Remote; import myappejb.entities.Question; @Remote public interface QuestionSessionRemote { void save(Question question) throws Exception; }   Choose File/Save All to save the changes made. That’s it. You just finished with your EJB module project. Adding JSF Framework to the Project Now that you have the entity and session beans created, let’s switch to the JSF_EJB_App-war project, where you’re building the web tier for the application.Before you can proceed to building JSF pages, you need to add the JavaServer Faces framework to the JSF_EJB_App-war project. To do this, follow the steps below: In the Project window, right click JSF_EJB_App-war project, and then choose Properties In the Project Properties window, select Frameworks from Categories, and click Add button. As a result, the Add a Framework dialog should appear In the Add a Framework dialog, choose JavaServer Faces and click OK Then click OK in the Project Properties dialog As a result, NetBeans adds the JavaServer Faces framework to the JSF_EJB_App-war project. Now if you extend the Configuration Files folder under the JSF_EJB_App-war project node in the Project window, you should see, among other configuration files, faces-config.xml there. Also notice the appearance of the welcomeJSF.jsp page in the Web Pages folder Creating JSF Managed Beans The next step is to create managed beans whose methods will be called from within the JSF pages. In this particular example, you need to create only one such bean: let’s call it QuestionController. This can be achieved by following the steps below: In the Project window, right click JSF_EJB_App-war project, and then choose New/Empty Java File In the New Empty Java File window, enter QuestionController as the class name and enter myappjsf.jsf in the Package field. Then, click Finish In the generated empty java file, insert the following code:   package myappjsf.jsf; import javax.ejb.EJB; import javax.faces.application.FacesMessage; import javax.faces.context.FacesContext; import myappejb.entities.Question; import myappejb.ejb.QuestionSessionBean; public class QuestionController { @EJB private QuestionSessionBean sbean; private Question question; public QuestionController() { } public Question getQuestion() { return question; } public void setQuestion(Question question) { this.question = question; } public String createSetup() { this.question = new Question(); this.question.setTrackno(null); return "question_create"; } public String create() { try { Integer trck = sbean.save(question); addSuccessMessage("Your question was successfully submitted."); } catch (Exception ex) { addErrorMessage(ex.getLocalizedMessage()); } return "created"; } public static void addErrorMessage(String msg) { FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg); FacesContext fc = FacesContext.getCurrentInstance(); fc.addMessage(null, facesMsg); } public static void addSuccessMessage(String msg) { FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg); FacesContext fc = FacesContext.getCurrentInstance(); fc.addMessage("successInfo", facesMsg); } }   Next, you need to add information about the newly created JSF managed bean to the faces-config.xml configuration file automatically generated when adding the JSF framework to the project. Find this file in the following folder: JSF_EJB_App-warWeb PagesWEB-INF in the Project window, and then insert the following tag between the and tags:   <managed-bean> <managed-bean-name>questionJSFBean</managed-bean-name> <managed-bean-class>myappjsf.jsf.QuestionController</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean>   Finally, make sure to choose File/Save All to save the changes made in faces-config.xml as well as in QuestionController.java. Creating JSF Pages To keep things simple, you create just one more JSF page: askquestion.jsp, where a user can submit a question. First, though, let’s modify the welcomeJSF.jsp page so that you can use it to move on to askquestion.jsp and then return to, once a question has been submitted. To achieve this, modify welcomeJSF.jsp as follows:   <%@page contentType="text/html"%> <%@page pageEncoding="UTF-8"%> <%@taglib prefix="f" uri="http://java.sun.com/jsf/core"%> <%@taglib prefix="h" uri="http://java.sun.com/jsf/html"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSP Page</title> </head> <body> <f:view> <h:messages errorStyle="color: red" infoStyle="color: green" layout="table"/> <h:form> <h1><h:outputText value="Ask us a question" /></h1> <h:commandLink action="#{questionJSFBean.createSetup}" value="New question"/> <br> </h:form> </f:view> </body> </html> Now you can move on and create askquestion.jsp. To do this, follow the steps below: In the Project window, right click JSF_EJB_App-war project, and then choose New/JSP In the New JSP File window, enter askquestion as the name for the page, and click Finish Modify the newly created askquestion.jsp so that it finally looks like this:   <%@page contentType="text/html"%> <%@page pageEncoding="UTF-8"%> <%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <html>     <head>         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />         <title>New Question</title>     </head>     <body>         <f:view>             <h:messages errorStyle="color: red" infoStyle="color: green" layout="table"/>             <h1>Your question, please!</h1>             <h:form>                 <h:panelGrid columns="2">                     <h:outputText value="Your Email:"/>                     <h:inputText id="userEmail" value= "#{questionJSFBean.question.userEmail}" title="Your Email" />                     <h:outputText value="Your Question:"/>                     <h:inputTextarea id="question" value= "#{questionJSFBean.question.question}"  title="Your Question" rows ="5" cols="35" />                 </h:panelGrid>                 <h:commandLink action="#{questionJSFBean.create}" value="Create"/>                 <br>                 <a href="/JSF_EJB_App-war/index.jsp">Back to index</a>             </h:form>         </f:view>     </body> </html>   The next step is to set page navigation. Turning back to the faces-config.xml configuration file, insert the following code there.   <navigation-rule> <navigation-case> <from-outcome>question_create</from-outcome> <to-view-id>/askquestion.jsp</to-view-id> </navigation-case> </navigation-rule> <navigation-rule> <navigation-case> <from-outcome>created</from-outcome> <to-view-id>/welcomeJSF.jsp</to-view-id> </navigation-case> </navigation-rule> Make sure that the above tags are within the <faces-config> and </faces-config> root tags. Check It You are ready now to check the application you just created. To do this, right-click JSF_EJB_App-ejb project in the Project window and choose Deploy Project. After the JSF_EJB_App-ejb project is successfully deployed, right click the JSF_EJB_App-war project and choose Run Project. As a result, the newly created application will run in a browser. As mentioned earlier, the application contains very few pages, actually three ones. For testing purposes, you can submit a question, and then check the questions database table to make sure that everything went as planned. Summary Both JSF and EJB 3 are popular technologies when it comes to building enterprise applications. This simple example illustrates how you can use these technologies together in a complementary way.
Read more
  • 0
  • 0
  • 3251
article-image-prepare-and-build
Packt
10 Dec 2012
13 min read
Save for later

Prepare and Build

Packt
10 Dec 2012
13 min read
(For more resources related to this topic, see here.) Let's take a look at the history and background of APEX. History and background APEX is a very powerful development tool, which is used to create web-based database-centric applications. The tool itself consists of a schema in the database with a lot of tables, views, and PL/SQL code. It's available for every edition of the database. The techniques that are used with this tool are PL/SQL, HTML, CSS, and JavaScript. Before APEX there was WebDB, which was based on the same techniques. WebDB became part of Oracle Portal and disappeared in silence. The difference between APEX and WebDB is that WebDB generates packages that generate the HTML pages, while APEX generates the HTML pages at runtime from the repository. Despite this approach APEX is amazingly fast. Because the database is doing all the hard work, the architecture is fairly simple. We only have to add a web server. We can choose one of the following web servers: Oracle HTTP Server (OHS) Embedded PL/SQL Gateway (EPG) APEX Listener APEX became available to the public in 2004 and then it was part of version 10g of the database. At that time it was called HTMLDB and the first version was 1.5. Before HTMLDB, it was called Oracle Flows , Oracle Platform, and Project Marvel. Throughout the years many versions have come out and at the time of writing the current version is 4.1.1. These many versions prove that Oracle has continuously invested in the development and support of APEX. This is important for the developers and companies who have to make a decision about which techniques to use in the future. According to Oracle, as written in their statement of direction, new versions of APEX will be released at least annually. The following screenshot shows the home screen of the current version of APEX: Home screen of APEX For the last few years, there is an increasing interest in the use of APEX from developers. The popularity came mainly from developers who found themselves comfortable with PL/SQL and wanted to easily enter the world of web-based applications. Oracle gave ADF a higher priority, because APEX was a no cost option of the database and with ADF (and all the related techniques and frameworks from Java), additional licenses could be sold. Especially now Oracle has pointed out APEX as one of the important tools for building applications in their Oracle Database Cloud Service, this interest will only grow. APEX shared a lot of the characteristics of cloud computing, even before cloud computing became popular. These characteristics include: Elasticity Roles and authorization Browser-based development and runtime RESTful web services (REST stands for Representational State Transfer) Multi-tenant Simple and fast to join APEX has outstanding community support, witnessed by the number of posts and threads on the Oracle forum. This forum is the most popular after the database and PL/SQL. Oracle itself has some websites, based on APEX. Among others there are the following: http://asktom.oracle.com http://shop.oracle.com http://cloud.oracle.com Oracle uses quite a few internal APEX applications. Oracle also provides a hosted version of APEX at http://apex.oracle.com. Users can sign up for free for a workspace to evaluate and experiment with the latest version of APEX. This environment is for evaluations and demonstrations only, there are no guarantees! Apex.oracle.com is a very popular service—more than 16,000 workspaces are active. To give an idea of the performance of APEX, the server used for this service used to be a Dell Poweredge 1950 with two Dual Core Xeon processors with 16 GB. Installing APEX In this section, we will discuss some additional considerations to take care of while installing APEX. The best source for the installation process is the Installation Guide of APEX. Runtime or full development environment On a production database, the runtime environment of APEX should be installed. This installation lacks the Application Builder and the SQL Workshop. Users can run applications, but the applications cannot be modified. The runtime environment of APEX can be administered using SQL*Plus and SQL Developer. The (web interface) options for importing an application, which are only available in a full development environment, can be used manually with the APEX_INSTANCE_ADMIN API. Using a runtime environment for production is recommended for security purposes, so that we can be certain that installed applications cannot be modified by anyone. On a development environment the full development environment can be installed with all the features available to the developers. Build status Besides the environment of APEX itself, the applications can also be installed in a similar way. When importing or exporting an application the Run Application Only or Run and Build Application options can be selected. Changing an application to Run Application Only can be done in the Application Builder by choosing Edit Application Properties. Changing the Build Status to Run and Build Application can only be done as the admin user of the workspace internal. In the APEX Administration Services, choose Manage Workspaces and then select Manage Applications | Build Status. Another setting related to the Runtime Only option could be used in the APEX Administration Services at instance level. Select Manage Instance and then select Security. Setting the property Disable Workspace Login to yes, acts as setting a Runtime Only environment, while still allowing instance administrators to log in to the APEX Administration Services. Tablespaces Following the install guide for the full development environment, at a certain moment, we have to run the following command, when logged in as SYS with the SYSDBA role, on the command line: @apexins tablespace_apex tablespace_files tablespace_temp images The command is explained as follows: tablespace_apex is the name of the tablespace that contains all the objects for the APEX application user. tablespace_files is the name of the tablespace that contains all the objects for the APEX files user. tablespace_temp is the name of the temporary tablespace of the database. images will be the virtual directory for APEX images. Oracle recommends using /i/ to support the future APEX upgrades. For the runtime environment, the command is as follows: @apxrtins tablespace_apex tablespace_files tablespace_temp images In the documentation, SYSAUX is given as an example for both tablespace_apex and tablespace_files. There are several reasons for not using SYSAUX for these tablespaces, but to use our own instead: SYSAUX is an important tablespace of the database itself We have more control over sizing and growth It is easier for a DBA to manage tablespace placement Contention in the SYSAUX tablespace is less occurring It's easier to clean-up older versions of APEX And last but not least, it's only an example Converting runtime environment into a full development environment and vice versa It's always possible to switch from a runtime to a production environment and vice versa. If you want to convert a runtime to a full development environment log in as SYS with the SYSDBA role and on the command line type @apxdvins.sql. For converting a full development to a runtime environment, type @apxdevrm—but export websheet applications first. Another way to restrict user access can be accomplished by logging in to the APEX Administration Services, where we can (among others) manage the APEX instance settings and all the workspaces. We can do that in two ways: http://server:port/apex/apex_admin: Log in with the administrator credentials http://server:port/apex/: Log in to the workspace internal, with the administrator credentials After logging in, perform the following steps: Go to Manage Instance. Select Security. Select the appropriate settings for Disable Administrator Login and Disable Workspace Login. These settings can also be set manually with the APEX_INSTANCE_ADMIN API. Choosing a web server When using a web-based development and runtime environment, we have to use a web server. Architecture of APEX The choice of a web server and the underlying architecture of the system has a direct impact on performance and scalability. Oracle provides us with three choices: Oracle HTTP Server (OHS) Embedded PL/SQL Gateway (EPG) APEX Listener Simply put, the web server maps the URL in a web browser to a procedure in the database. Everything the procedure prints with sys.htp package, is sent to the browser of the user. This is the concept used by tools such as WebDB and APEX. OHS The OHS is the oldest of the three. It's based on the Apache HTTP Server and uses a custom Apache Module named as mod_plsql: Oracle HTTP Server In release 10g of the database, OHS was installed with the database on the same machine. Upward to the release 11g, this is not the case anymore. If you want to install the OHS, you have to install the web tier part of WebLogic. If you install it on the same machine as the database, it's free of extra licence costs. This installation takes up a lot of space and is rather complex, compared with the other two. On the other hand, it's very fl exible and it has a proven track record. Configuration is done with the text files. EPG The EPG is part of XML DB and lives inside the database. Because everything is in the database, we have to use the dbms_xdb and dbms_epg PL/SQL packages to configure the EPG. Another implication is that all images and other files are stored inside the database, which can be accessed with PL/SQL or FTP, for example: Embedded PL/SQL gateway The architecture is very simple. It's not possible to install the EPG on a different machine than the database. From a security point of view, this is not the recommended architecture for real-life Internet applications and in most cases the EPG is used in development, test, or other internal environments with few users. APEX Listener APEX Listener is the newest of the three, it's still in development and with every new release more features are added to it. In the latest version, RESTful APIs can be created by configuring resource templates. APEX Listener is a Java application with a very small footprint. APEX Listener can be installed in a standalone mode, which is ideal for development and testing purposes. For production environments, the APEX Listener can be deployed by using a J2EE compliant Application Server such as Glassfish, WebLogic, or Oracle Containers for J2EE: APEX Listener Configuration of the APEX Listener is done in a browser. With some extra configuration, uploading of Excel into APEX collections can be achieved. In future release, other functionalities, such as OAuth 2.0 and ICAP virus scanner integration, have been announced. Configuration options of the APEX Listener Like OHS, an architectural choice can be made if we want to install APEX Listener on the same machine as the database. For large public applications, it's better to use a separate web server. Many documents and articles have been written about choosing the right web server. If you read between the lines, you'll see that Oracle more or less recommends the use of APEX Listener. Given the functionality, enhanced security, file caching, fl exibility of deployment possibilities, and feature announcements makes it the best choice. Creating a second administrator When installing APEX, by default the workspace Internal with the administrator user Admin is created. Some users know more than the average end user. Also, developers have more knowledge than the average user. Imagine that such users try to log in to either the APEX Administration Services or the normal login page with the workspace Internal and administrator Admin, and consequently use the wrong password. As a consequence, the Admin account would be locked after a number of login attempts. This is a very annoying situation, especially when it happens often. Big companies and APEX Hosting companies with many workspaces and a lot of anonymous users or developers may suffer from this. Fortunately there is an easy solution, creating a second administrator account. Login attempt in workspace Internal as Admin If the account is already locked, we have to unlock it first. This can be easily done by running the apxchpwd.sql script, which can be found in the main Apex directory of the unzipped installation file of APEX: Start SQL*Plus and connect as sys with the sysdba role Run the script by entering @apxchpwd.sql. Follow the instructions and enter a new password. Now we are ready to create a second administrator account. This can be done in two ways, using the web interface or the command line. APEX web interface Follow these steps to create a new administrator, using the browser. First, we need to log in to the APEX Administrator Services at http://server:port/apex/. Log in to the workspace Internal, with the administrator credentials After logging in, perform the following steps: Go to Manage Workspaces. Select Existing Workspaces. You can also select the edit icon of the workspace Internal to inspect the settings. You cannot change them. Select Cancel to return to the previous screen. Select the workspace Internal by clicking on the name. Select Manage Users. Here you can see the user Admin. You can also select the user Admin to change the password. Other settings cannot be changed. Select Cancel or Apply Changes to return to the previous screen. Select Create User. Make sure that Internal is selected in the Workspace field and APEX_xxxxxx is selected in Default Schema, and that the new user is an administrator. xxxxxx has to match your APEX scheme version in the database, for instance, APEX_040100. Click on Create to finish. Settings for the new administrator Command line When we still have access, we can use the web interface of APEX. If not we can use the command line: Start SQL*Plus and connect as SYS with the SYSDBA role. Unlock the APEX_xxxxxx account by issuing the following command: alter user APEX_xxxxxx account unlock; Connect to the APEX_xxxxxx account. If you don't remember your password, you can just reset it, without impacting the APEX instance. Execute the following (use your own username, e-mail, and password): BEGIN wwv_flow_api.set_security_group_id (p_security_group_id=>10); wwv_flow_fnd_user_api.create_fnd_user( p_user_name => 'second_admin', p_email_address => 'email@company.com', p_web_password => 'second_admin_password') ; END; / COMMIT / The new administrator is created. Connect again as SYS with the SYSDBA role and lock the account again with the following command: alter user APEX_xxxxxx account lock; Now you can log in to the Internal workspace with your newly created account and you'll be asked to change your password. Other accounts When an administrator of a developer workspace loses his/her password or has a locked account, you can bring that account back to life by following these steps: Log in to the APEX Administrator Services Go to Manage Workspace. Select Existing Workspaces. Select the workspace. Select Manage Users. Select the user, change the password, and unlock the user. A developer or an APEX end user account can be managed by the administrator of the workspace from the workspace itself. Follow these steps to do so: Log in to the workspace. Go to Administration. Select the user, change the password, and unlock the user.
Read more
  • 0
  • 0
  • 3251

article-image-basic-dijit-knowledge-dojo
Packt
22 Oct 2009
7 min read
Save for later

Basic Dijit Knowledge in Dojo

Packt
22 Oct 2009
7 min read
All Dijits can be subclassed to change parts of their behavior, and then used as the original Dijits, or you can create your own Dijits from scratch and include existing Dijits (Forms, buttons, calendars, and so on) in a hierarchical manner. All Dijits can be created in either of the following two ways: Using the dojoType markup property inside selected tags in the HTML page. Programmatic creation inside any JavaScript. For instance, if you want to have a ColorPalette in your page, you can write the following: <div dojoType="dijit.ColorPalette"></div> But you also need to load the required Dojo packages, which consist of the ColorPalette and any other things it needs. This is generally done in a script statement in the <head> part of the HTML page, along with any CSS resources and the djConfig declaration. So a complete example would look like this: <html> <head> <title>ColorPalette</title> <style> @import "dojo-1.1b1/dojo/resources/dojo.css"; @import "dojo-1.1b1/dijit/themes/tundra/tundra.css"; </style> <script type="text/javascript"> djConfig= { parseOnLoad: true } </script> <script type="text/javascript" src="dojo-1.1b1/dojo/dojo.js"></script> <script type="text/javascript"> dojo.require("dojo.parser"); dojo.require("dijit.ColorPalette"); </script> </head> <body class=”tundra”> <div dojoType="dijit.ColorPalette"></div> </body> </html> Obviously, this shows a simple color palette, which can be told to call a function when a choice has been made. But if we start from the top, I've chosen to include two CSS files in the <style> tag. The first one, dojo.css, is a reset.css, which gives lists, table elements, and various other things their defaults. The file itself is quite small and well commented. The second file is called tundra.css and is a wrapper around lots of other stylesheets; some are generic for the theme it represents, but most are specific for widgets or widget families. The two ways to create Dijits So putting a Dojo widget in your page is very simple. If you would want the ColorPalette dynamically in a script instead, remove the highlighted line just before the closing body tag and instead write the following: <script> new dijit.ColorPalette({}, dojo.byId('myPalette')); </script> This seems fairly easy, but what's up with the empty object literal ( {} ) as the first argument? Well, as some Dijits take few arguments and others more, all arguments to a Dijit get stuffed into the first argument and the others, the last argument is (if needed) the DOM node which the Dijit shall replace with its own content somewhere in the page. The default is, for all Dijits, that if we only give one argument to the constructor, this will be taken as the DOM node where the Dijit is to be created. Let's see how to create a more complex Dijit in our page, a NumberSpinner. This will create a NumberSpinner that is set at the value '200' and which has '500' as a maximum, showing no decimals. To create this NumberSpinner dynamically, we would write the following: <input type="text" name="date1" value="2008-12-30" dojoType="dijit.form.DateTextBox"/> One rather peculiar feature of markup-instantiation of Dijits is that you can use almost any kind of tag for the Dijit. The Dijit will replace the element with its own template when it is initialized. Certain Dijits work in a more complicated fashion and do not replace child nodes of the element where they're defined, but wrap them instead. However, each Dijit has support for template HTML which will be inserted, with variable substitutions whenever that Dijit is put in the page. This is a very powerful feature, since when you start creating your own widgets, you will have an excellent system in place already which constrains where things will be put and how they are called. This means that when you finish your super-complicated graph drawing widget and your client or boss wants three more just like it on the same page, you just slap up three more tags which have the dojoType defining your widget. How do I find my widget? You already know that you can use dojo.byId('foo') as a shorter version of document.getElementById('foo'). If you still think that dojo.byId is too long, you can create a shorthand function like this: var $ = dojo.byId; And then use $('foo') instead of dojo.byId for simple DOM node lookup. But Dijits also seem to have an id. Are those the same as the ids of the DOM node they reside in or what? Well, the answer is both yes and no. All created Dijit widgets have a unique id. That id can be the same string as the id that defines the DOM node where they're created, but it doesn't have to be. Suppose that you create a Dijit like this: <div id='foo' dojoType='dijit._Calendar'></div> The created Dijit will have the same Dijit id as the id of the DOM node it was created in, because no others were given. But can you define another id for the widget than for its DOM node? Sure thing. There's a magic attribute called widgetId. So we could do the following: <div id='foo' dojoType='dijit._Calendar' widgetId='bar'></div> This would give the widget the id of 'bar'. But, really, what is the point? Why would we care the widget / Dijit has some kind of obscure id? All we really need is the DOM node, right? Not at all. Sure, you might want to reach out and do bad things to the DOM node of a widget, but that object will not be the widget and have none of its functions. If you want to grab hold of a widget instance after it is created, you need to know its widget id, so you can call the functions defined in the widget. So it's almost its entire reason to exist! So how do I get hold of a widget obejct now that I have its id? By using dijit.byId(). These two functions look pretty similar, so here is a clear and easy to find (when browsing the book) explanation: dojo.byId(): Returns the DOM node for the given id. dijit.byId(): Returns the widget object for the given widget id. Just one more thing. What happens if we create a widget and don't give either a DOM or widget id? Does the created widget still get an id? How do we get at it? Yes, the widget will get a generated id, if we write the following: <div dojoType='dijit._Calendar'></div> The widget will get a widget id like this: dijit__Calendar_0. The id will be the string of the file or namespace path down to the .js file which declares the widget, with / exchanged to _, and with a static widget counter attached to the end.
Read more
  • 0
  • 0
  • 3249

Packt
27 Feb 2015
25 min read
Save for later

Putting It All Together – Community Radio

Packt
27 Feb 2015
25 min read
In this article by Andy Matthews, author of the book Creating Mobile Apps with jQuery Mobile, Second Edition, we will see a website where listeners will be greeted with music from local, independent bands across several genres and geographic regions. Building this will take many of the skills, and we'll pepper in some new techniques that can be used in this new service. Let's see what technology and techniques we could bring to bear on this venture. In this article, we will cover: A taste of Balsamiq Organizing your code An introduction to the Web Audio API Prompting the user to install your app New device-level hardware access To app or not to app Three good reasons for compiling an app (For more resources related to this topic, see here.) A taste of Balsamiq Balsamiq (http://www.balsamiq.com/) is a very popular User Experience (UX) tool for rapid prototyping. It is perfect for creating and sharing interactive mockups: When I say very popular, I mean lots of major names that you're used to seeing. Over 80,000 companies create their software with the help of Balsamiq Mockups. So, let's take a look at what the creators of a community radio station might have in mind. They might start with a screen which looks like this; a pretty standard implementation. It features an icon toolbar at the bottom and a listview element in the content: Ideally, we'd like to keep this particular implementation as pure HTML/JavaScript/CSS. That way, we could compile it into a native app at some point, using PhoneGap. However, we'd like to stay true to the Don't Repeat Yourself (DRY) principle. That means, that we're going to want to inject this footer onto every page without using a server-side process. To that end, let's set up a hidden part of our app to contain all the global elements that we may want: <div id="globalComponents">   <div data-role="navbar" class="bottomNavBar">       <ul>           <li><a data-icon="music" href="#stations_by_region" data-transition="slideup">stations</a></li>         <li><a data-icon="search" href="#search_by_artist" data-transition="slideup">discover</a></li>           <li><a data-icon="calendar" href="#events_by_location" data-transition="slideup">events</a></li>           <li><a data-icon="gear" href="#settings" data-transition="slideup">settings</a></li>       </ul>   </div></div> We'll keep this code at the bottom of the page and hide it with a simple CSS rule in the stylesheet, #globalComponents{display:none;}. Now, we'll insert this global footer into each page, just before they are created. Using the clone() method (shown in the next code snippet) ensures that not only are we pulling over a copy of the footer, but also any data attached with it. In this way, each page is built with the exact same footer, just like it is in a server-side include. When the page goes through its normal initialization process, the footer will receive the same markup treatment as the rest of the page: /************************* The App************************/var radioApp = {universalPageBeforeCreate:function(){   var $page = $(this);   if($page.find(".bottomNavBar").length == 0){     $page.append($("#globalComponents .bottomNavBar").clone());   }}}/************************* The Events************************///Interface Events$(document).on("pagebeforecreate", "[data- "role="page"]",radioApp.universalPageBeforeCreate); Look at what we've done here in this piece of JavaScript code. We're actually organizing our code a little more effectively. Organizing your code I believe in a very pragmatic approach to coding, which leads me to use more simple structures and a bare minimum of libraries. However, there are values and lessons to be learned out there. MVC, MVVM, MV* For the last couple of years, serious JavaScript developers have been bringing backend development structures to the web, as the size and scope of their project demanded a more regimented approach. For highly ambitious, long-lasting, in-browser apps, this kind of structured approach can help. This is even truer if you're on a larger team. MVC stands for Model-View-Controller ( see http://en.wikipedia.org/wiki/Model–view–controller), MVVM is for Model View ViewModel (see http://en.wikipedia.org/wiki/Model_View_ViewModel), and MV* is shorthand for Model View Whatever and is the general term used to sum up this entire movement of bringing these kinds of structures to the frontend. Some of the more popular libraries include: Backbone.JS (http://backbonejs.org/): An adapter and sample of how to make Backbone play nicely with jQuery Mobile can be found at http://demos.jquerymobile.com/1.4.5/backbone-requirejs. Ember (http://emberjs.com/): An example for Ember can be found at https://github.com/LuisSala/emberjs-jqm. AngularJS (https://angularjs.org/): Angular also has adapters for jQM in progress. There are several examples at https://github.com/tigbro/jquery-mobile-angular-adapter. Knockout: (http://knockoutjs.com/). A very nice comparison of these, and more, is at http://readwrite.com/2014/02/06/angular-backbone-ember-best-javascript-framework-for-you. MV* and jQuery Mobile Yes, you can do it!! You can add any one of these MV* frameworks to jQuery Mobile and make as complex an app as you like. Of them all, I lean toward the Ember platform for desktop and Angular for jQuery Mobile. However, I'd like to propose another alternative. I'm not going to go in-depth into the concepts behind MVC frameworks. Ember, Angular, and Backbone, all help you to separate the concerns of your application into manageable pieces, offering small building blocks with which to create your application. But, we don't need yet another library/framework to do this. It is simple enough to write code in a more organized fashion. Let's create a structure similar to what I've started before: //JavaScript Document/******************** The Application*******************//******************** The Events*******************//******************** The Model*******************/ The application Under the application section, let's fill in some of our app code and give it a namespace. Essentially, namespacing is taking your application-specific code and putting it into its own named object, so that the functions and variables won't collide with other potential global variables and functions. It keeps you from polluting the global space and helps preserve your code from those who are ignorant regarding your work. Granted, this is JavaScript and people can override anything they wish. However, this also makes it a whole lot more intentional to override something like the radioApp.getStarted function, than simply creating your own function called getStarted. Nobody is going to accidentally override a namespaced function. /******************** The application*******************/var radioApp = {settings:{   initialized:false,   geolocation:{     latitude:null,     longitude:null,   },   regionalChoice:null,   lastStation:null},getStarted:function(){   location.replace("#initialize");},fireCustomEvent:function(){   var $clicked = $(this);   var eventValue = $clicked.attr("data-appEventValue");   var event = new jQuery.Event($(this).attr("data-appEvent"));   if(eventValue){ event.val = eventValue; }   $(window).trigger(event);},otherMethodsBlahBlahBlah:function(){}} Pay attention, in particular, to the fireCustomEvent. function With that, we can now set up an event management system. At its core, the idea is pretty simple. We'd like to be able to simply put tag attributes on our clickable objects and have them fire events, such as all the MV* systems. This fits the bill perfectly. It would be quite common to set up a click event handler on a link, or something, to catch the activity. This is far simpler. Just an attribute here and there and you're wired in. The HTML code becomes more readable too. It's easy to see how declarative this makes your code: <a href="javascript://" data-appEvent="playStation" data- appEventValue="country">Country</a> The events Now, instead of watching for clicks, we're listening for events. You can have as many parts of your app as you like registering themselves to listen for the event, and then execute appropriately. As we fill out more of our application, we'll start collecting a lot of events. Instead of letting them get scattered throughout multiple nested callbacks and such, we'll be keeping them all in one handy spot. In most JavaScript MV* frameworks, this part of the code is referred to as the Router. Hooked to each event, you will see nothing but namespaced application calls: /******************** The events*******************///Interface events$(document).on("click", "[data-appEvent]",radioApp.fireCustomEvent);"$(document).on("pagecontainerbeforeshow","[data-role="page"]",radioApp.universalPageBeforeShow);"$(document).on("pagebeforecreate","[data-role="page"]",radioApp.universalPageBeforeCreate);"$(document).on("pagecontainershow", "#initialize",radioApp.getLocation);"$(document).on("pagecontainerbeforeshow", "#welcome",radioApp.initialize);//Application events$(window).on("getStarted",radioApp.getStarted);$(window).on("setHomeLocation",radioApp.setHomeLocation);$(window).on("setNotHomeLocation",radioApp.setNotHomeLocation);$(window).on("playStation",radioApp.playStation); Notice the separation of concerns into interface events and application events. We're using this as a point of distinction between events that are fired as a result of natural jQuery Mobile events (interface events), and events that we have thrown (application events). This may be an arbitrary distinction, but for someone who comes along later to maintain your code, this could come in handy. The model The model section contains the data for your application. This is typically the kind of data that is pulled in from your backend APIs. It's probably not as important here, but it never hurts to namespace what's yours. Here, we have labeled our data as the modelData label. Any information we pull in from the APIs can be dumped right into this object, like we've done here with the station data: /******************** The Model*******************/var modelData = {station:{   genres:[       {       display:"Seattle Grunge",       genreId:12,       genreParentId:1       }   ],   metroIds[14,33,22,31],   audioIds[55,43,26,23,11]}} Pair this style of programming with client-side templating, and you'll be looking at some highly maintainable, well-structured code. However, there are some features that are still missing. Typically, these frameworks will also provide bindings for your templates. This means that you only have to render the templates once. After that, simply updating your model object will be enough to cause the UI to update itself. The problem with these bound templates, is that they update the HTML in a way that would be perfect for a desktop application. But remember, jQuery Mobile does a lot of DOM manipulation to make things happen. In jQuery Mobile, a listview element starts like this: <ul data-role="listview" data-inset="true"><li><a href="#stations">Local Stations</a></li></ul> After the normal DOM manipulation, you get this: <ul data-role="listview" data-inset="true" data-theme="b" style="margin-top:0" class="ui-listview ui-listview-inset ui- corner-all ui-shadow"> <li data-corners="false" data-shadow="false" data- iconshadow="true" data-wrapperels="div" data-icon="arrow-r" data- iconpos="right" data-theme="b" class="ui-btn ui-btn-icon-right ui- li-has-arrow ui-li ui-corner-top ui-btn-up-b">       <div class="ui-btn-inner ui-li ui-corner-top">           <div class="ui-btn-text">               <a href="#stations" class="ui-link-inherit">Local Stations</a>           </div><span class="ui-icon ui-icon-arrow-r ui-icon- shadow">&nbsp;</span>       </div>   </li></ul> And that's just a single list item. You really don't want to include all that junk in your templates; so what you need to do, is just add your usual items to the listview element and then call the .listview("refresh") function. Even if you're using one of the MV* systems, you'll still have to either find, or write, an adapter that will refresh the listviews when something is added or deleted. With any luck, these kinds of things will be solved at the platform level soon. Until then, using a real MV* system with jQM will be a pain in the posterior. Introduction to the Web Audio API The Web Audio API is a fairly new development and, at the time of writing this, only existed within the mobile space on Mobile Safari and Chrome for Android (http://caniuse.com/#feat=audio-api). The Web Audio API is available on the latest versions of desktop Chrome, Safari, and Firefox, so you can still do your initial test coding there. It's only a matter of time before this is built into other major platforms. Most of the code for this part of the project, and the full explanation of the API, can be found at http://tinyurl.com/webaudioapi2014. Let's use feature detection to branch our capabilities: function init() {if("webkitAudioContext" in window) {   context = new webkitAudioContext();   // an analyzer is used for the spectrum   analyzer = context.createAnalyzer();   analyzer.smoothingTimeConstant = 0.85;   analyzer.connect(context.destination);   fetchNextSong();} else {   //do the old stuff}} The original code for this page was designed to kick off simultaneous downloads for every song in the queue. With a fat connection, this would probably be OK. Not so much on mobile. Because of the limited connectivity and bandwidth, it would be better to just chain downloads to ensure a better experience and a more respectful use of bandwidth: function fetchNextSong() {var request = new XMLHttpRequest();var nextSong = songs.pop();if(nextSong){   request = new XMLHttpRequest();   // the underscore prefix is a common naming convention   // to remind us that the variable is developer-supplied   request._soundName = nextSong;   request.open("GET", PATH + request._soundName + ".mp3", " true);   request.responseType = "arraybuffer";   request.addEventListener("load", bufferSound, false);   request.send();}} Now, the bufferSound function just needs to call the fetchNextSong function after buffering, as shown in the following code snippet: function bufferSound(event) {   var request = event.target;   context.decodeAudioData(request.response, function onSuccess(decodedBuffer) {       myBuffers.push(decodedBuffer);       fetchNextSong();   }, function onFailure() {       alert("Decoding the audio buffer failed");   });} One last thing we need to change from the original, is telling the buffer to pull the songs in the order that they were inserted: function playSound() {   // create a new AudioBufferSourceNode   var source = context.createBufferSource();   source.buffer = myBuffers.shift();  source.loop = false;   source = routeSound(source);   // play right now (0 seconds from now)   // can also pass context.currentTime   source.start(0); mySpectrum = setInterval(drawSpectrum, 30);   mySource = source;} For anyone on iOS, this solution is pretty nice. There is a lot more to this API for those who want to dig in. With this out-of-the-box example, you get a nice canvas-based audio analyzer that gives you a very nice professional look, as the audio levels bounce to the music. Slider controls are used to change the volume, the left-right balance, and the high-pass filter. If you don't know what a high-pass filter is, don't worry; I think that filter's usefulness went the way of the cassette deck. Regardless, it's fun to play with: The Web Audio API is a very serious piece of business. This example was adapted from the example on Apple's site. It only plays one sound. However, the Web Audio API was designed with the idea of making it possible to play multiple sounds, alter them in multiple ways, and even dynamically generate sounds using JavaScript. In the meantime, if you want to see this proof of concept in jQuery Mobile, you will find it in the example source in the webaudioapi.html file. For an even deeper look at what is coming, you can check the docs at https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html. Prompting the user to install your app Now, let's take a look at how we can prompt our users to download the Community Radio app to their home screens. It is very likely that you've seen it before; it's the little bubble that pops up and instructs the user with the steps to install the app. There are many different projects out there, but the best one that I have seen is a derivative of the one started by Google. Much thanks and respect to Okamototk on GitHub (https://github.com/okamototk) for taking and improving it. Okamototk evolved the bubble to include several versions of Android, legacy iOS, and even BlackBerry. You can find his original work at https://github.com/okamototk/jqm-mobile-bookmark-bubble. However, unless you can read Japanese, or enjoy translating it. Don't worry about annoying your customers too much. With this version, if they dismiss the bookmarking bubble three times, they won't see it again. The count is stored in HTML5 LocalStorage; so, if they clear out the storage, they'll see the bubble again. Thankfully, most people out there don't even know that can be done, so it won't happen very often. Usually, it's geeks like us that clear things like LocalStorage and cookies, and we know what we're getting into when we do it. In my edition of the code, I've combined all the JavaScript into a single file meant to be placed between your import of jQuery and jQuery Mobile. At the top, the first non-commented line is: page_popup_bubble="#welcome"; This is what you would change to be your own first page, or where you want the bubble to pop up. In my version, I have hardcoded the font color and text shadow properties into the bubble. This was needed, because in jQM the font color and text shadow color vary, based on the theme you're using. Consequently, in jQuery Mobile's original default A theme (white text on a black background), the font was showing up as white with a dark shadow on top of a white bubble. With my modified version, for older jQuery Mobile versions, it will always look right. We just need to be sure we've set up our page with the proper links in the head, and that our images are in place: <link rel="apple-touch-icon-precomposed" sizes="144x144" href="images/album144.png"><link rel="apple-touch-icon-precomposed" sizes="114x114" href="images/album114.png"><link rel="apple-touch-icon-precomposed" sizes="72x72" href="images/album72.png"><link rel="apple-touch-icon-precomposed" href="images/album57.png"><link rel="shortcut icon" href="img/images/album144.png"> Note the Community Radio logo here. The logo is pulled from our link tags marked with rel="apple-touch-icon-precomposed" and injected into the bubble. So, really, the only thing in the jqm_bookmark_bubble.js file that you would need to alter is the page_popup_bubble function. New device-level hardware access New kinds of hardware-level access are coming to our mobile browsers every year. Here is a look at some of what you can start doing now, and what's on the horizon. Not all of these are applicable to every project, but if you think creatively, you can probably find innovative ways to use them. Accelerometers Accelerometers are the little doo-dads inside your phone that measure the phone's orientation in space. To geek out on this, read http://en.wikipedia.org/wiki/Accelerometer. This goes beyond the simple orientation we've been using. This is true access to the accelerometers, in detail. Think about the user being able to shake their device, or tilting it as a method of interaction with your app. Maybe, Community Radio is playing something they don't like and we can give them a fun way to rage against the song. Something such as, shake a song to never hear it again. Here is a simple marble rolling game somebody made as a proof of concept. See http://menscher.com/teaching/woaa/examples/html5_accelerometer.html. Camera Apple's iOS 8 and Android's Lollipop can both access photos on their filesystems as well as the cameras. Granted, these are the latest and greatest versions of these two platforms. If you intend to support the many woefully out of date Android devices (2.3, 2.4) that are still being sold off the shelves as if brand new, then you're going to want to go with a native compilation such as PhoneGap or Apache Cordova to get that capability: <input type="file" accept="image/*"><input type="file" accept="video/*"> The following screenshot has iOS to the left and Android to the right: APIs on the horizon Mozilla is doing a lot to push the mobile web API envelope. You can check out what's on the horizon here: https://wiki.mozilla.org/WebAPI. To app or not to app, that is the question Should you or should you not compile your project into a native app? Here are some things to consider. Raining on the parade (take this seriously) When you compile your first project into an app, there is a certain thrill that you get. You did it! You made a real app! It is at this point that we need to remember the words of Dr. Ian Malcolm from the movie Jurassic Park (Go watch it again. I'll wait): "You stood on the shoulders of geniuses to accomplish something as fast as you could, and before you even knew what you had, you patented it, and packaged it, and slapped it on a plastic lunchbox, and now [bangs on the table] you're selling it, you wanna sell it. Well... your scientists were so preoccupied with whether or not they could that they didn't stop to think if they should."                                                                                                  – Dr. Ian Malcolm These words are very close to prophetic for us. In the end, their own creation ate most of the guests for lunch. According to this report from August 2012 http://www.webpronews.com/over-two-thirds-of-the-app-store-has-never-been-downloaded-2012-08 (and several others like it that I've seen before), over two-thirds of all apps on the app stores have never been downloaded. Not even once! So, realistically, app stores are where most projects go to die. Even if your app is discovered, the likelihood that anyone will use it for any significant period of time is astonishingly small. According to this article in Forbes (http://tech.fortune.cnn.com/2009/02/20/the-half-life-of-an-iphone-app/), most apps are abandoned in the space of minutes and never opened again. Paid apps last about twice as long, before either being forgotten or removed. Games have some staying power, but let's be honest, jQuery Mobile isn't exactly a compelling gaming platform, is it?? The Android world is in terrible shape. Devices can still be purchased running ancient versions of the OS, and carriers and hardware partners are not providing updates to them in anything even resembling a timely fashion. If you want to monitor the trouble you could be bringing upon yourself by embracing a native strategy, look here: http://developer.android.com/about/dashboards/index.html: You can see how fractured the Android landscape is, as well as how many older versions you'll probably have to support. On the flip side, if you're publishing strictly to the web, then every time your users visit your site, they'll be on the latest edition using the latest APIs, and you'll never have to worry about somebody using some out-of-date version. Do you have a security patch you need to apply? You can do it in seconds. If you're on the Apple app store, this patch could take days or even weeks. Three good reasons for compiling an app Yes, I know I just finished telling you about your slim chances of success and the fire and brimstone you will face for supporting apps. However, here are a few good reasons to make a real app. In fact, in my opinion, they're the only acceptable reasons. The project itself is the product This is the first and only sure sign that you need to package your project as an app. I'm not talking about selling things through your project. I'm talking about the project itself. It should be made into an app. May the force be with you. Access to native only hardware capabilities GPS and camera are reliably available for the two major platforms in their latest editions. iOS even supports accelerometers. However, if you're looking for more than this, you'll need to compile down to an app to get access to these APIs. Push notifications Do you like them? I don't know about you, but I get way too many push notifications; any app that gets too pushy either gets uninstalled or its notifications are completely turned off. I'm not alone in this. However, if you simply must have push notifications and can't wait for the web-based implementation, you'll have to compile an app. Supporting current customers Ok, this one is a stretch, but if you work in corporate America, you're going to hear it. The idea is that you're an established business and you want to give mobile support to your clients. You or someone above you has read a few whitepapers and/or case studies that show that almost 50 percent of people search in the app stores first. Even if that were true (which I'm still not sold on), you're talking to a businessperson. They understand money, expenses, and escalated maintenance. Once you explain to them the cost, complexity, and potential ongoing headaches of building and testing for all the platforms and their OS versions in the wild, it becomes a very appealing alternative to simply put out a marketing push to your current customers that you're now supporting mobile, and all they have to do is go to your site on their mobile device. Marketing folks are always looking for reasons to toot their horns at customers anyway. Marketing might still prefer to have the company icon on the customer's device to reinforce brand loyalty, but this is simply a matter of educating them that it can be done without an app. You still may not be able to convince all the right people that apps are the wrong way to go when it comes to customer support. If you can't do it on your own, slap them on their heads with a little Jakob Nielson. If they won't listen to you, maybe they'll listen to him. I would defy anyone who says that the Nielsen Norman Group doesn't know what they're saying. See http://www.nngroup.com/articles/mobile-sites-vs-apps-strategy-shift/ for the following quote: "Summary: Mobile apps currently have better usability than mobile sites, but forthcoming changes will eventually make a mobile site the superior strategy." So the $64,000 question becomes: are we making something for right now or for the future? If we're making it for right now, what are the criteria that should mark the retirement of the native strategy? Or do we intend to stay locked on it forever? Don't go into that war without an exit strategy. Summary I don't know about you, but I'm exhausted. I really don't think there's any more that can be said about jQuery Mobile, or its supporting technologies at this time. You've got examples on how to build things for a whole host of industries, and ways to deploy it through the web. At this point, you should be quoting Bob the Builder. Can we build it? Yes, we can! I hope this article has assisted and/or inspired you to go and make something great. I hope you change the world and get filthy stinking rich doing it. I'd love to hear your success stories as you move forward. To let me know how you're doing, or to let me know of any errata, or even if you just have some questions, please don't hesitate to email us directly at http://andy@commadelimited.com. Now, go be awesome! Resources for Article: Further resources on this subject: Tips and Tricks for Working with jQuery and WordPress [article] Building a Custom Version of jQuery [article] jQuery UI 1.8: The Accordion Widget [article]
Read more
  • 0
  • 0
  • 3248
article-image-python-data-structures
Packt
09 Mar 2016
23 min read
Save for later

Python Data Structures

Packt
09 Mar 2016
23 min read
In this article written by Dusty Phillips, author of the book Python 3 Object-oriented Programming - Second Edition we'll be discussing the object-oriented features of data structures, when they should be used instead of a regular class, and when they should not be used. In particular, we'll be covering: Tuples and named tuples Dictionaries (For more resources related to this topic, see here.) Empty objects Let's start with the most basic Python built-in, one that we've seen many times already, the one that we've extended in every class we have created: the object. Technically, we can instantiate an object without writing a subclass: >>> o = object() >>> o.x = 5 Traceback (most recent call last):   File "<stdin>", line 1, in <module> AttributeError: 'object' object has no attribute 'x' Unfortunately, as you can see, it's not possible to set any attributes on an object that was instantiated directly. This isn't because the Python developers wanted to force us to write our own classes, or anything so sinister. They did this to save memory; a lot of memory. When Python allows an object to have arbitrary attributes, it takes a certain amount of system memory to keep track of what attributes each object has, for storing both the attribute name and its value. Even if no attributes are stored, memory is allocated for potential new attributes. Given the dozens, hundreds, or thousands of objects (every class extends object) in a typical Python program; this small amount of memory would quickly become a large amount of memory. So, Python disables arbitrary properties on object, and several other built-ins, by default. It is possible to restrict arbitrary properties on our own classes using slots. You now have a search term if you are looking for more information. In normal use, there isn't much benefit to using slots, but if you're writing an object that will be duplicated thousands of times throughout the system, they can help save memory, just as they do for object. It is, however, trivial to create an empty object class of our own; we saw it in our earliest example: class MyObject:     pass And, as we've already seen, it's possible to set attributes on such classes: >>> m = MyObject() >>> m.x = "hello" >>> m.x 'hello' If we wanted to group properties together, we could store them in an empty object like this. But we are usually better off using other built-ins designed for storing data. It has been stressed that classes and objects should only be used when you want to specify both data and behaviors. The main reason to write an empty class is to quickly block something out, knowing we'll come back later to add behavior. It is much easier to adapt behaviors to a class than it is to replace a data structure with an object and change all references to it. Therefore, it is important to decide from the outset if the data is just data, or if it is an object in disguise. Once that design decision is made, the rest of the design naturally falls into place. Tuples and named tuples Tuples are objects that can store a specific number of other objects in order. They are immutable, so we can't add, remove, or replace objects on the fly. This may seem like a massive restriction, but the truth is, if you need to modify a tuple, you're using the wrong data type (usually a list would be more suitable). The primary benefit of tuples' immutability is that we can use them as keys in dictionaries, and in other locations where an object requires a hash value. Tuples are used to store data; behavior cannot be stored in a tuple. If we require behavior to manipulate a tuple, we have to pass the tuple into a function (or method on another object) that performs the action. Tuples should generally store values that are somehow different from each other. For example, we would not put three stock symbols in a tuple, but we might create a tuple of stock symbol, current price, high, and low for the day. The primary purpose of a tuple is to aggregate different pieces of data together into one container. Thus, a tuple can be the easiest tool to replace the "object with no data" idiom. We can create a tuple by separating the values with a comma. Usually, tuples are wrapped in parentheses to make them easy to read and to separate them from other parts of an expression, but this is not always mandatory. The following two assignments are identical (they record a stock, the current price, the high, and the low for a rather profitable company): >>> stock = "FB", 75.00, 75.03, 74.90 >>> stock2 = ("FB", 75.00, 75.03, 74.90) If we're grouping a tuple inside of some other object, such as a function call, list comprehension, or generator, the parentheses are required. Otherwise, it would be impossible for the interpreter to know whether it is a tuple or the next function parameter. For example, the following function accepts a tuple and a date, and returns a tuple of the date and the middle value between the stock's high and low value: import datetime def middle(stock, date):     symbol, current, high, low = stock     return (((high + low) / 2), date)   mid_value, date = middle(("FB", 75.00, 75.03, 74.90),         datetime.date(2014, 10, 31)) The tuple is created directly inside the function call by separating the values with commas and enclosing the entire tuple in parenthesis. This tuple is then followed by a comma to separate it from the second argument. This example also illustrates tuple unpacking. The first line inside the function unpacks the stock parameter into four different variables. The tuple has to be exactly the same length as the number of variables, or it will raise an exception. We can also see an example of tuple unpacking on the last line, where the tuple returned inside the function is unpacked into two values, mid_value and date. Granted, this is a strange thing to do, since we supplied the date to the function in the first place, but it gave us a chance to see unpacking at work. Unpacking is a very useful feature in Python. We can group variables together to make storing and passing them around simpler, but the moment we need to access all of them, we can unpack them into separate variables. Of course, sometimes we only need access to one of the variables in the tuple. We can use the same syntax that we use for other sequence types (lists and strings, for example) to access an individual value: >>> stock = "FB", 75.00, 75.03, 74.90 >>> high = stock[2] >>> high 75.03 We can even use slice notation to extract larger pieces of tuples: >>> stock[1:3] (75.00, 75.03) These examples, while illustrating how flexible tuples can be, also demonstrate one of their major disadvantages: readability. How does someone reading this code know what is in the second position of a specific tuple? They can guess, from the name of the variable we assigned it to, that it is high of some sort, but if we had just accessed the tuple value in a calculation without assigning it, there would be no such indication. They would have to paw through the code to find where the tuple was declared before they could discover what it does. Accessing tuple members directly is fine in some circumstances, but don't make a habit of it. Such so-called "magic numbers" (numbers that seem to come out of thin air with no apparent meaning within the code) are the source of many coding errors and lead to hours of frustrated debugging. Try to use tuples only when you know that all the values are going to be useful at once and it's normally going to be unpacked when it is accessed. If you have to access a member directly or using a slice and the purpose of that value is not immediately obvious, at least include a comment explaining where it came from. Named tuples So, what do we do when we want to group values together, but know we're frequently going to need to access them individually? Well, we could use an empty object, as discussed in the previous section (but that is rarely useful unless we anticipate adding behavior later), or we could use a dictionary (most useful if we don't know exactly how many or which specific data will be stored), as we'll cover in the next section. If, however, we do not need to add behavior to the object, and we know in advance what attributes we need to store, we can use a named tuple. Named tuples are tuples with attitude. They are a great way to group read-only data together. Constructing a named tuple takes a bit more work than a normal tuple. First, we have to import namedtuple, as it is not in the namespace by default. Then, we describe the named tuple by giving it a name and outlining its attributes. This returns a class-like object that we can instantiate with the required values as many times as we want: from collections import namedtuple Stock = namedtuple("Stock", "symbol current high low") stock = Stock("FB", 75.00, high=75.03, low=74.90) The namedtuple constructor accepts two arguments. The first is an identifier for the named tuple. The second is a string of space-separated attributes that the named tuple can have. The first attribute should be listed, followed by a space (or comma if you prefer), then the second attribute, then another space, and so on. The result is an object that can be called just like a normal class to instantiate other objects. The constructor must have exactly the right number of arguments that can be passed in as arguments or keyword arguments. As with normal objects, we can create as many instances of this "class" as we like, with different values for each. The resulting namedtuple can then be packed, unpacked, and otherwise treated like a normal tuple, but we can also access individual attributes on it as if it were an object: >>> stock.high 75.03 >>> symbol, current, high, low = stock >>> current 75.00 Remember that creating named tuples is a two-step process. First, use collections.namedtuple to create a class, and then construct instances of that class. Named tuples are perfect for many "data only" representations, but they are not ideal for all situations. Like tuples and strings, named tuples are immutable, so we cannot modify an attribute once it has been set. For example, the current value of my company's stock has gone down since we started this discussion, but we can't set the new value: >>> stock.current = 74.98 Traceback (most recent call last):   File "<stdin>", line 1, in <module> AttributeError: can't set attribute If we need to be able to change stored data, a dictionary may be what we need instead. Dictionaries Dictionaries are incredibly useful containers that allow us to map objects directly to other objects. An empty object with attributes to it is a sort of dictionary; the names of the properties map to the property values. This is actually closer to the truth than it sounds; internally, objects normally represent attributes as a dictionary, where the values are properties or methods on the objects (see the __dict__ attribute if you don't believe me). Even the attributes on a module are stored, internally, in a dictionary. Dictionaries are extremely efficient at looking up a value, given a specific key object that maps to that value. They should always be used when you want to find one object based on some other object. The object that is being stored is called the value; the object that is being used as an index is called the key. We've already seen dictionary syntax in some of our previous examples. Dictionaries can be created either using the dict() constructor or using the {} syntax shortcut. In practice, the latter format is almost always used. We can prepopulate a dictionary by separating the keys from the values using a colon, and separating the key value pairs using a comma. For example, in a stock application, we would most often want to look up prices by the stock symbol. We can create a dictionary that uses stock symbols as keys, and tuples of current, high, and low as values like this: stocks = {"GOOG": (613.30, 625.86, 610.50),           "MSFT": (30.25, 30.70, 30.19)} As we've seen in previous examples, we can then look up values in the dictionary by requesting a key inside square brackets. If the key is not in the dictionary, it will raise an exception: >>> stocks["GOOG"] (613.3, 625.86, 610.5) >>> stocks["RIM"] Traceback (most recent call last):   File "<stdin>", line 1, in <module> KeyError: 'RIM' We can, of course, catch the KeyError and handle it. But we have other options. Remember, dictionaries are objects, even if their primary purpose is to hold other objects. As such, they have several behaviors associated with them. One of the most useful of these methods is the get method; it accepts a key as the first parameter and an optional default value if the key doesn't exist: >>> print(stocks.get("RIM")) None >>> stocks.get("RIM", "NOT FOUND") 'NOT FOUND' For even more control, we can use the setdefault method. If the key is in the dictionary, this method behaves just like get; it returns the value for that key. Otherwise, if the key is not in the dictionary, it will not only return the default value we supply in the method call (just like get does), it will also set the key to that same value. Another way to think of it is that setdefault sets a value in the dictionary only if that value has not previously been set. Then it returns the value in the dictionary, either the one that was already there, or the newly provided default value. >>> stocks.setdefault("GOOG", "INVALID") (613.3, 625.86, 610.5) >>> stocks.setdefault("BBRY", (10.50, 10.62, 10.39)) (10.50, 10.62, 10.39) >>> stocks["BBRY"] (10.50, 10.62, 10.39) The GOOG stock was already in the dictionary, so when we tried to setdefault it to an invalid value, it just returned the value already in the dictionary. BBRY was not in the dictionary, so setdefault returned the default value and set the new value in the dictionary for us. We then check that the new stock is, indeed, in the dictionary. Three other very useful dictionary methods are keys(), values(), and items(). The first two return an iterator over all the keys and all the values in the dictionary. We can use these like lists or in for loops if we want to process all the keys or values. The items() method is probably the most useful; it returns an iterator over tuples of (key, value) pairs for every item in the dictionary. This works great with tuple unpacking in a for loop to loop over associated keys and values. This example does just that to print each stock in the dictionary with its current value: >>> for stock, values in stocks.items(): ...     print("{} last value is {}".format(stock, values[0])) ... GOOG last value is 613.3 BBRY last value is 10.50 MSFT last value is 30.25 Each key/value tuple is unpacked into two variables named stock and values (we could use any variable names we wanted, but these both seem appropriate) and then printed in a formatted string. Notice that the stocks do not show up in the same order in which they were inserted. Dictionaries, due to the efficient algorithm (known as hashing) that is used to make key lookup so fast, are inherently unsorted. So, there are numerous ways to retrieve data from a dictionary once it has been instantiated; we can use square brackets as index syntax, the get method, the setdefault method, or iterate over the items method, among others. Finally, as you likely already know, we can set a value in a dictionary using the same indexing syntax we use to retrieve a value: >>> stocks["GOOG"] = (597.63, 610.00, 596.28) >>> stocks['GOOG'] (597.63, 610.0, 596.28) Google's price is lower today, so I've updated the tuple value in the dictionary. We can use this index syntax to set a value for any key, regardless of whether the key is in the dictionary. If it is in the dictionary, the old value will be replaced with the new one; otherwise, a new key/value pair will be created. We've been using strings as dictionary keys, so far, but we aren't limited to string keys. It is common to use strings as keys, especially when we're storing data in a dictionary to gather it together (instead of using an object with named properties). But we can also use tuples, numbers, or even objects we've defined ourselves as dictionary keys. We can even use different types of keys in a single dictionary: random_keys = {} random_keys["astring"] = "somestring" random_keys[5] = "aninteger" random_keys[25.2] = "floats work too" random_keys[("abc", 123)] = "so do tuples"   class AnObject:     def __init__(self, avalue):         self.avalue = avalue   my_object = AnObject(14) random_keys[my_object] = "We can even store objects" my_object.avalue = 12 try:     random_keys[[1,2,3]] = "we can't store lists though" except:     print("unable to store listn")   for key, value in random_keys.items():     print("{} has value {}".format(key, value)) This code shows several different types of keys we can supply to a dictionary. It also shows one type of object that cannot be used. We've already used lists extensively, and we'll be seeing many more details of them in the next section. Because lists can change at any time (by adding or removing items, for example), they cannot hash to a specific value. Objects that are hashable basically have a defined algorithm that converts the object into a unique integer value for rapid lookup. This hash is what is actually used to look up values in a dictionary. For example, strings map to integers based on the characters in the string, while tuples combine hashes of the items inside the tuple. Any two objects that are somehow considered equal (like strings with the same characters or tuples with the same values) should have the same hash value, and the hash value for an object should never ever change. Lists, however, can have their contents changed, which would change their hash value (two lists should only be equal if their contents are the same). Because of this, they can't be used as dictionary keys. For the same reason, dictionaries cannot be used as keys into other dictionaries. In contrast, there are no limits on the types of objects that can be used as dictionary values. We can use a string key that maps to a list value, for example, or we can have a nested dictionary as a value in another dictionary. Dictionary use cases Dictionaries are extremely versatile and have numerous uses. There are two major ways that dictionaries can be used. The first is dictionaries where all the keys represent different instances of similar objects; for example, our stock dictionary. This is an indexing system. We use the stock symbol as an index to the values. The values could even have been complicated self-defined objects that made buy and sell decisions or set a stop-loss, rather than our simple tuples. The second design is dictionaries where each key represents some aspect of a single structure; in this case, we'd probably use a separate dictionary for each object, and they'd all have similar (though often not identical) sets of keys. This latter situation can often also be solved with named tuples. These should typically be used when we know exactly what attributes the data must store, and we know that all pieces of the data must be supplied at once (when the item is constructed). But if we need to create or change dictionary keys over time or we don't know exactly what the keys might be, a dictionary is more suitable. Using defaultdict We've seen how to use setdefault to set a default value if a key doesn't exist, but this can get a bit monotonous if we need to set a default value every time we look up a value. For example, if we're writing code that counts the number of times a letter occurs in a given sentence, we could do this: def letter_frequency(sentence):     frequencies = {}     for letter in sentence:         frequency = frequencies.setdefault(letter, 0)         frequencies[letter] = frequency + 1     return frequencies Every time we access the dictionary, we need to check that it has a value already, and if not, set it to zero. When something like this needs to be done every time an empty key is requested, we can use a different version of the dictionary, called defaultdict: from collections import defaultdict def letter_frequency(sentence):     frequencies = defaultdict(int)     for letter in sentence:         frequencies[letter] += 1     return frequencies This code looks like it couldn't possibly work. The defaultdict accepts a function in its constructor. Whenever a key is accessed that is not already in the dictionary, it calls that function, with no parameters, to create a default value. In this case, the function it calls is int, which is the constructor for an integer object. Normally, integers are created simply by typing an integer number into our code, and if we do create one using the int constructor, we pass it the item we want to create (for example, to convert a string of digits into an integer). But if we call int without any arguments, it returns, conveniently, the number zero. In this code, if the letter doesn't exist in the defaultdict, the number zero is returned when we access it. Then we add one to this number to indicate we've found an instance of that letter, and the next time we find one, that number will be returned and we can increment the value again. The defaultdict is useful for creating dictionaries of containers. If we want to create a dictionary of stock prices for the past 30 days, we could use a stock symbol as the key and store the prices in list; the first time we access the stock price, we would want it to create an empty list. Simply pass list into the defaultdict, and it will be called every time an empty key is accessed. We can do similar things with sets or even empty dictionaries if we want to associate one with a key. Of course, we can also write our own functions and pass them into the defaultdict. Suppose we want to create a defaultdict where each new element contains a tuple of the number of items inserted into the dictionary at that time and an empty list to hold other things. Nobody knows why we would want to create such an object, but let's have a look: from collections import defaultdict num_items = 0 def tuple_counter():     global num_items     num_items += 1     return (num_items, [])   d = defaultdict(tuple_counter) When we run this code, we can access empty keys and insert into the list all in one statement: >>> d = defaultdict(tuple_counter) >>> d['a'][1].append("hello") >>> d['b'][1].append('world') >>> d defaultdict(<function tuple_counter at 0x82f2c6c>, {'a': (1, ['hello']), 'b': (2, ['world'])}) When we print dict at the end, we see that the counter really was working. This example, while succinctly demonstrating how to create our own function for defaultdict, is not actually very good code; using a global variable means that if we created four different defaultdict segments that each used tuple_counter, it would count the number of entries in all dictionaries, rather than having a different count for each one. It would be better to create a class and pass a method on that class to defaultdict. Counter You'd think that you couldn't get much simpler than defaultdict(int), but the "I want to count specific instances in an iterable" use case is common enough that the Python developers created a specific class for it. The previous code that counts characters in a string can easily be calculated in a single line: from collections import Counter def letter_frequency(sentence):     return Counter(sentence) The Counter object behaves like a beefed up dictionary where the keys are the items being counted and the values are the number of such items. One of the most useful functions is the most_common() method. It returns a list of (key, count) tuples ordered by the count. You can optionally pass an integer argument into most_common() to request only the top most common elements. For example, you could write a simple polling application as follows: from collections import Counter   responses = [     "vanilla",     "chocolate",     "vanilla",     "vanilla",     "caramel",     "strawberry",     "vanilla" ]   print(     "The children voted for {} ice cream".format(         Counter(responses).most_common(1)[0][0]     ) ) Presumably, you'd get the responses from a database or by using a complicated vision algorithm to count the kids who raised their hands. Here, we hardcode it so that we can test the most_common method. It returns a list that has only one element (because we requested one element in the parameter). This element stores the name of the top choice at position zero, hence the double [0][0] at the end of the call. I think they look like a surprised face, don't you? Your computer is probably amazed it can count data so easily. It's ancestor, Hollerith's Tabulating Machine for the 1890 US census, must be so jealous! Summary We've covered several built-in data structures and attempted to understand how to choose one for specific applications. Sometimes, the best thing we can do is create a new class of objects, but often, one of the built-ins provides exactly what we need. When it doesn't, we can always use inheritance or composition to adapt them to our use cases. We can even override special methods to completely change the behavior of built-in syntaxes. Be sure to pick up the full title, Python 3 Object-oriented Programming - Second Edition, to continue your learning in the world of OOP Python. If you want to go above and beyond then there’s no better way than building on what you’ve discovered with Mastering Object-oriented Python and Learning Object-Oriented Programming too! Resources for Article:   Further resources on this subject: Python LDAP applications - extra LDAP operations and the LDAP URL library [article] Exception Handling in MySQL for Python [article] Data Transactions Made Easy with MySQL and Python [article]
Read more
  • 0
  • 0
  • 3247

article-image-developing-applications-jboss-and-hibernate-part-1
Packt
19 Jan 2010
4 min read
Save for later

Developing Applications with JBoss and Hibernate: Part 1

Packt
19 Jan 2010
4 min read
Introducing Hibernate Hibernate provides a bridge between the database and the application by persisting application objects in the database, rather than requiring the developer to write and maintain lots of code to store and retrieve objects. The main configuration file, hibernate.cfg.xml, specifies how Hibernate obtains database connections, either from a JNDI DataSource or from a JDBC connection pool. Additionally, the configuration file defines the persistent classes, which are backed by mapping definition files. This is a sample hibernate.cfg.xml configuration file that is used to handle connections to a MySQL database, mapping the com.sample.MySample class. <hibernate-configuration><session-factory><property name="connection.username">user</property><property name="connection.password">password</property><property name="connection.url"> jdbc:mysql://localhost/database</property><property name="connection.driver_class"> com.mysql.jdbc.Driver</property><property name="dialect"> org.hibernate.dialect.MySQLDialect</property><mapping resource="com/sample/MyClass.hbm.xml"/></session-factory></hibernate-configuration> From our point of view, it is important to know that Hibernate applications can coexist in both the managed environment and the non-managed environment. An application server is a typical example of a managed environment that provides services to hosting applications, such as connection pooling and transaction. On the other hand, a non-managed application refers to standalone applications, such as Swing Java clients that typically lack any built-in service. In this article, we will focus on managed environment applications, installed on JBoss Application Server. You will not need to download any library to your JBoss installation. As a matter of fact, JBoss persistence layer is designed around Hibernate API, so it already contains all the core libraries. Creating a Hibernate application You can choose different strategies for building a Hibernate application. For example, you could start building Java classes and map files from scratch, and then let Hibernate generate the database schema accordingly. You can also start from a database schema and reverse engineer it into Java classes and Hibernate mapping files. We will choose the latter option, which is also the fastest. Here's an overview of our application. In this example, we will design an employee agenda divided into departments. The persistence model will be developed with Hibernate, using the reverse engineering facet of JBoss tools. We will then need an interface for recording our employees and departments, and to query them as well. The web interface will be developed using a simple Model-View-Controller (MVC) pattern and basic JSP 2.0 and servlet features. The overall architecture of this system resembles the AppStore application that has been used to introduce JPA. As a matter of fact, this example can be used to compare the two persistence models and to decide which option best suits your project needs. We have added a short section at the end of this example to stress a few important points about this choice. Setting up the database schema The overall architecture of this system resembles the AppStore application that has been used to introduce JPA. As a matter of fact, this example can be used to compare the two persistence models and to decide which option best suits your project needs. We have added a short section at the end of this example to stress a few important points about this choice. CREATE schema hibernate;GRANT ALL PRIVILEGES ON hibernate.* TO 'jboss'@'localhost' WITH GRANTOPTION;CREATE TABLE `hibernate`.`department` (`department_id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,`department_name` VARCHAR(45) NOT NULL,PRIMARY KEY (`department_id`))ENGINE = InnoDB;CREATE TABLE `hibernate`.`employee` (`employee_id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,`employee_name` VARCHAR(45) NOT NULL,`employee_salary` INTEGER UNSIGNED NOT NULL,`employee_department_id` INTEGER UNSIGNED NOT NULL,PRIMARY KEY (`employee_id`),CONSTRAINT `FK_employee_1` FOREIGN KEY `FK_employee_1` (`employee_department_id`)REFERENCES `department` (`department_id`)ON DELETE CASCADEON UPDATE CASCADE)ENGINE = InnoDB; With the first Data Definition Language (DDL) command, we have created a schema named Hibernate that will be used to store our tables. Then, we have assigned the necessary privileges on the Hibernate schema to the user jboss. Finally, we created a table named department that contains the list of company units, and another table named employee that contains the list of workers. The employee table references the department with a foreign key constraint.
Read more
  • 0
  • 0
  • 3246
Modal Close icon
Modal Close icon